関数呼び出しでオプションの引数をスキップするにはどうすればよいですか?


94

OK PHPで引数をスキップする方法を完全に忘れてしまいました。

私が持っているとしましょう:

function getData($name, $limit = '50', $page = '1') {
    ...
}

中央のパラメーターがデフォルト値(つまり、「50」)になるように、この関数をどのように呼び出しますか?

getData('some name', '', '23');

上記は正しいでしょうか?これが機能しないようです。


1
@チャックはあなたが正確に何を探しているのですか?これを実装するための回避策またはクラスのように... ...
Rizier123

@ Rizier123 PHPの現在のバージョンが引数のスキップをサポートしているかどうかを確認するよう求めています(他の言語と同様)。現在の回答は古くなっている可能性があります。バウンティの説明から:「現在の回答は5年前のものです。現在のバージョンのPHPは状況を変えますか?」
チャックルバット、

1
@チャックその後、おそらく答えは次のようになります。回避策/コードがないと、機能を利用できません。
Rizier123

ここでのすべての答えは、呼び出される関数を制御できることを前提としているようです。その関数がライブラリまたはフレームワークの一部である場合、引数3が必要な場合は引数2に何かを指定する以外に選択肢はありません。唯一のオプションは、関数のソースを調べてデフォルト値を複製することです。
Snapey

スキップすることはできませんが、を使用してデフォルトの引数を渡すことができますReflectionFunction。その答えを同様の質問に投稿しました。
デビッド

回答:


55

あなたの投稿は正しいです。

残念ながら、パラメーターリストの最後でオプションのパラメーターを使用する必要がある場合は、最後のパラメーターまですべてを指定する必要があります。一般的に、組み合わせて一致させる場合は、''またはのデフォルト値を指定し、それらがデフォルト値であるnull場合は関数内で使用しないでください。


1
例を挙げていただけますか?
私は

2
@iammeはgetData関数$limit = is_numeric($limit) ? $limit : '50';の最初に行います
Kamafeather 2018年

40

falseまたはのようなデフォルトを指定する以外に、引数を「スキップ」する方法はありませんnull

これに関してPHPには構文上の砂糖がないので、次のようなものがよく見られます。

checkbox_field(array(
    'name' => 'some name',
    ....
));

これは、雄弁にコメントで述べたように、配列を使用して名前付き引数をエミュレートしています。

これにより、究極の柔軟性が得られますが、場合によっては必要ないこともあります。少なくとも、ほとんどの場合は予期しないと思われるものを引数リストの最後に移動できます。


2
私は「このようなもの」を「配列を使用して名前付き引数をエミュレートする」FWIWとして識別します。:)
カオス

3
より柔軟であるにもかかわらず、設定する必要がある/設定できるパラメーターを覚えておく必要があります(シグニチャーにはないため)。したがって、最終的には見た目ほど役に立たないかもしれませんが、もちろんこれはコンテキストに依存します。
Felix Kling

では、そのようなシナリオのベストプラクティスは何でしょうか。
アダムグラント

39

いいえ、この方法で引数をスキップすることはできません。引数の受け渡しのみ省略できますは、パラメーターリストの最後にある場合にます。

これに関する公式の提案がありました: https //wiki.php.net/rfc/skipparams、拒否されました。提案ページは、このトピックに関する他のSOの質問にリンクしています。


それでは、PHP関数はどのようにオプションのパラメーターを増やしたり減らしたりしますか?
私は

2
PHPはデフォルトのパラメータ値をサポートしています。ただし、これらのパラメーターはリストの最後になければなりません。
Cristik


2
ジャーク。私をとても怒らせます。他の人が要求する機能が気に入らない場合は、使用しないでください。インターネットは最悪の場合もあります。
リーサクソン

@LeeSaxonの問題は可読性と移植性です。1)誰かがパラメータをスキップすることに決め、誰かがコードをデバッグすることでこの事実を見逃した場合、大きな混乱が生じます。2)新しいコードは、メジャーオーバーホールがなければ古いバージョンでは機能せず、ミスの可能性が非常に高くなります。
マークウォルシュ

6

オプションの引数をスキップできることに関しては何も変更されていませんが、正しい構文とスキップしたい引数にNULLを指定できるようにするには、次のようにします。

define('DEFAULT_DATA_LIMIT', '50');
define('DEFAULT_DATA_PAGE', '1');

/**
 * getData
 * get a page of data 
 *
 * Parameters:
 *     name - (required) the name of data to obtain
 *     limit - (optional) send NULL to get the default limit: 50
 *     page - (optional) send NULL to get the default page: 1
 * Returns:
 *     a page of data as an array
 */

function getData($name, $limit = NULL, $page = NULL) {
    $limit = ($limit===NULL) ? DEFAULT_DATA_LIMIT : $limit;
    $page = ($page===NULL) ? DEFAULT_DATA_PAGE : $page;
    ...
}

これはこのようにしてgetData('some name',NULL,'23');呼び出すことができます。将来この関数を呼び出す人は、毎回デフォルトを宣言したり、定数を宣言したりする必要はありません。


1
厳密な比較が必要な場合があります($ limit === null)
roelleor

4

簡単な答えは「いいえ」です。しかし、なぜ議論を再整理するときにスキップしてこれを達成するのですか?

あなたのものは「デフォルトの関数引数の誤った使用法」であり、期待どおりに機能しません。

PHPドキュメントの補足:

デフォルトの引数を使用する場合、デフォルトはデフォルト以外の引数の右側にある必要があります。そうでなければ、物事は期待どおりに動作しません。

以下を検討してください。

function getData($name, $limit = '50', $page = '1') {
    return "Select * FROM books WHERE name = $name AND page = $page limit $limit";
}

echo getData('some name', '', '23');   // won't work as expected

出力は次のようになります。

"Select * FROM books WHERE name = some name AND page = 23 limit"

デフォルトの関数引数の正しい使用法は次のようになります。

function getData($name, $page = '1', $limit = '50') {
    return "Select * FROM books WHERE name = $name AND page = $page limit $limit";
}

echo getData('some name', '23');  // works as expected

出力は次のようになります。

"Select * FROM books WHERE name = some name AND page = 23 limit 50"

非デフォルトの後に右側にデフォルトを置くと、定義されていない/指定されていない場合、その変数のデフォルト値が常に返されます。ここにリンクがありますれます。参照用とこれらの例の。

編集:null他の人が提案しているように設定することは機能する可能性があり、別の代替手段ですが、必要なものに適合しない場合があります。定義されていない場合、デフォルトは常にnullに設定されます。


これは明確に説明された構文の説明を提供するため、最良の答えです!ありがとうございました!
クリスチャン

2

スキップされたパラメーターについては(デフォルトである必要があります)、デフォルトのパラメーターを使用して安全性を確保します。

(デフォルトのパラメーターが ''または同様の場所でnullを解決するか、その逆の場合、問題が発生します...)


2

上記のように、パラメーターをスキップすることはできません。この回答は、コメントに入れるには大きすぎる補遺を提供するために書きました。

@Frank Nocke 、デフォルトのパラメーターで関数を呼び出すこと提案しているため、たとえば

function a($b=0, $c=NULL, $d=''){ //...

あなたは使うべきです

$var = a(0, NULL, 'ddd'); 

これは、最初の2つの($bおよび$c)パラメーターを省略した場合と機能的に同じになります。

どれがデフォルトかは明らかではありません( 0であるかはデフォルト値を提供するために入力されていますか、それとも重要ですか?)

関数(またはメソッド)の作成者がデフォルト値を変更できる場合、デフォルト値の問題が外部(または組み込み)関数に関連する危険もあります。したがって、プログラムで呼び出しを変更しないと、意図せずにその動作が変更される可能性があります。

一部の回避策はDEFAULT_A_B、「関数AのBパラメータのデフォルト値」や「省略」パラメータなどのグローバル定数を定義することです。

$var = a(DEFAULT_A_B, DEFAULT_A_C, 'ddd');

クラスの場合、クラス定数を定義すると、それらがグローバルスコープの一部になるため、より簡単でエレガントになります。

class MyObjectClass {
  const DEFAULT_A_B = 0;

  function a($b = self::DEFAULT_A_B){
    // method body
  }
} 
$obj = new MyObjectClass();
$var = $obj->a(MyObjectClass::DEFAULT_A_B); //etc.

このデフォルト定数はコード全体で1回だけ定義されるため(メソッド宣言にも値はありません)、予期しない変更が発生した場合は、常に関数/メソッドに正しいデフォルト値を指定します。

この溶液の透明性は、より良い生のデフォルト値(のような供給よりももちろんありNULL0読者に何も言わないなど)。

(私はのような呼び出し$var = a(,,'ddd');が最良の選択肢であることに同意します)


2

引数をスキップすることはできませんが、配列パラメーターを使用でき、パラメーターの配列である1つのパラメーターのみを定義する必要があります。

function myfunction($array_param)
{
    echo $array_param['name'];
    echo $array_param['age'];
    .............
}

また、必要な数のパラメーターを追加できます。パラメーターを定義する必要はありません。関数を呼び出すときは、次のようにパラメーターを配置します。

myfunction(array("name" => "Bob","age" => "18", .........));

0

他の誰もがすでに言ったように、あなたが望むものは、関数にコード行を追加することなしにPHPでは不可能です。

ただし、次のコードを関数の先頭に配置して、機能を取得できます。

foreach((new ReflectionFunction(debug_backtrace()[0]["function"]))->getParameters() as $param) {
    if(empty(${$param->getName()}) && $param->isOptional())
        ${$param->getName()} = $param->getDefaultValue();
}

したがって、基本的にはdebug_backtrace()このコードが配置されている関数名を取得し、新しいReflectionFunctionオブジェクトを作成してすべての関数引数をループします。

ループでは、関数の引数がempty()ANDであり、引数が「オプション」である(デフォルト値があることを意味する)かどうかを確認します。はいの場合、デフォルト値を引数に割り当てます。

Demo


0

制限をnullに設定します

function getData($name, $limit = null, $page = '1') {
    ...
}

そしてその関数を呼び出す

getData('some name', null, '23');

制限を設定したい場合は、引数として渡すことができます

getData('some name', 50, '23');

0

以前アドバイスしたように、何も変更されませんでした。ただし、パラメーターが多すぎる(特にオプションのパラメーターが多い)ことは、コードの臭いを示す強力な指標です。

おそらくあなたの関数はやりすぎです:

// first build context
$dataFetcher->setPage(1);
// $dataFetcher->setPageSize(50); // not used here
// then do the job
$dataFetcher->getData('some name');

一部のパラメーターは論理的にグループ化できます。

$pagination = new Pagination(1 /*, 50*/);
getData('some name', $pagination);
// Java coders will probably be familiar with this form:
getData('some name', new Pagination(1));

最後の手段として、いつでもアドホックパラメータオブジェクトを導入できます

$param = new GetDataParameter();
$param->setPage(1);
// $param->setPageSize(50); // not used here
getData($param);

(これは、あまり正式でないパラメーター配列手法の美化されたバージョンです)

場合によっては、パラメーターをオプションにする理由そのものが間違っていることがあります。この例では、$page本当にオプションであることを意図していますか?いくつかの文字を保存すると本当に違いがありますか?

// dubious
// it is not obvious at first sight that a parameterless call to "getData()"
// returns only one page of data
function getData($page = 1);

// this makes more sense
function log($message, $timestamp = null /* current time by default */);

0

このスニペット:

    function getData($ name、$ options){
       $ default = array(
            「限界」=> 50、
            'ページ' => 2
        );
        $ args = array_merge($ default、$ options);
        print_r($ args);
    }

    getData( 'foo'、array());
    getData( 'foo'、array( 'limit' => 2));
    getData( 'foo'、array( 'limit' => 10、 'page' => 10));

答えは:

     アレイ
    (
        [制限] => 50
        [ページ] => 2
    )
    アレイ
    (
        [制限] => 2
        [ページ] => 2
    )
    アレイ
    (
        [制限] => 10
        [ページ] => 10
    )


2
いいね。しかし、少しの説明が役に立ちます。
showdev

良い答えですが、オプションのパラメーターを省略したい場合は、次のようにします:function getData($ name、$ args = array()){$ defaults = array( 'limit':=> 50、 'page' => 2) ; $ args = array_merge($ defaults、$ args); これで、次のような最初のパラメーターのみでこの関数を呼び出すことができます。getData( 'foo');
EchoSin 2016年

0

これは私がすることです:

<?php

    function getData($name, $limit = '', $page = '1') {
            $limit = (EMPTY($limit)) ? 50 : $limit;
            $output = "name=$name&limit=$limit&page=$page";
            return $output;
    }

     echo getData('table');

    /* output name=table&limit=50&page=1 */

     echo getData('table',20);

    /* name=table&limit=20&page=1 */

    echo getData('table','',5);

    /* output name=table&limit=50&page=5 */

    function getData2($name, $limit = NULL, $page = '1') {
            $limit = (ISSET($limit)) ? $limit : 50;
            $output = "name=$name&limit=$limit&page=$page";
            return $output;
    }

    echo getData2('table');

    // /* output name=table&limit=50&page=1 */

    echo getData2('table',20);

    /* output name=table&limit=20&page=1 */

    echo getData2('table',NULL,3);

    /* output name=table&limit=50&page=3 */

?>

これが誰かを助けることを願っています


0

これは、いくつかの技術的に有能な答えを持つ古い質問のようなものですが、PHPの最新の設計パターンの1つであるオブジェクト指向プログラミングを求めています。プリミティブスカラーデータ型のコレクションを注入する代わりに、関数が必要とするすべてのデータを含む「注入されたオブジェクト」の使用を検討してください。 http://php.net/manual/en/language.types.intro.php

注入されたオブジェクトには、プロパティ検証ルーチンなどがある場合があります。注入されたオブジェクトへのデータのインスタンス化と注入がすべての検証に合格できない場合、コードはすぐに例外をスローし、アプリケーションは扱いにくい処理を回避できます。不完全なデータが含まれている可能性があります。

展開する前に、注入されたオブジェクトにタイプヒントを付けて、間違いを見つけることができます。アイデアのいくつかは、数年前のこの記事にまとめられています。

https://www.experts-exchange.com/articles/18409/Using-Named-Parameters-in-PHP-Function-Calls.html


0

オプションのパラメーターでファクトリーを作成する必要がありましたが、私の回避策は、nullの合体演算子を使用することでした:

public static function make(
    string $first_name = null,
    string $last_name = null,
    string $email = null,
    string $subject = null,
    string $message = null
) {
    $first_name = $first_name ?? 'First';
    $last_name  = $last_name ?? 'Last';
    $email      = $email ?? 'foo@bar.com';
    $subject    = $subject ?? 'Some subject';
    $message    = $message ?? 'Some message';
}

使用法:

$factory1 = Factory::make('First Name Override');
$factory2 = Factory::make(null, 'Last Name Override');
$factory3 = Factory::make(null, null, null, null 'Message Override');

かわいらしいことではありませんが、ファクトリーでテストに使用するのに適したパターンかもしれません。


-1

これを試して。

function getData($name, $limit = NULL, $page = '1') {
               if (!$limit){
                 $limit = 50;
               }
}

getData('some name', '', '23');

-2

関数呼び出しで中間パラメーターをスキップすることはできません。しかし、これで回避できます:

function_call('1', '2', '3'); // Pass with parameter.
function_call('1', null, '3'); // Pass without parameter.

関数:

function function_call($a, $b='50', $c){
    if(isset($b)){
        echo $b;
    }
    else{
        echo '50';
    }
}

$ cにもデフォルト値が必要なことを除いて、なぜ反対票を投じたのかわかりません(オプションの引数の後に必須の引数を指定することはできません)。
フランクフォルテ

-2

@IbrahimLawalが指摘したように。それらをnull値に設定することをお勧めします。渡さnullれた値が、定義したデフォルトを使用しているかどうかを確認してください。

<?php
define('DEFAULT_LIMIT', 50);
define('DEFAULT_PAGE', 1);

function getData($name, $limit = null, $page = null) {
    $limit = is_null($limit) ? DEFAULT_LIMIT : $limit;
    $page = is_null($page) ? DEFAULT_PAGE : $page;
    ...
}
?>

お役に立てれば。


単に応答を複製しました。むしろ、あなたはそれに賛成票を投じるか、コメントしたかもしれません。
Ibrahim Lawal

-6
getData('some name');

それらを渡さないでください、そしてデフォルト値は受け入れられます

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.