関数でのデフォルト引数の使用


177

PHP関数のデフォルト値について混乱しています。次のような関数があるとします。

function foo($blah, $x = "some value", $y = "some other value") {
    // code here!
}

$ xにデフォルトの引数を使用し、$ yに別の引数を設定したい場合はどうなりますか?

私はさまざまな方法で実験をしており、混乱しているだけです。たとえば、次の2つを試しました。

foo("blah", null, "test");
foo("blah", "", "test");

しかし、これらは両方とも$ xの適切なデフォルト引数にはなりません。また、変数名で設定しようとしました。

foo("blah", $x, $y = "test");   

私はこのようなものが機能することを完全に期待していました。しかし、私が期待したようにはまったく機能しません。私が何をしても、関数を呼び出すたびに、とにかくデフォルトの引数を入力しなければならないようです。そして、私は明らかな何かを見逃しているに違いありません。


68
あなたはおそらく何も見逃していないでしょう、PHP開発者はおそらくこれを見逃しているでしょう。
Matti Virkkunen、2012

それは興味深い質問です。あなたが述べたように、私は実際にこれを行う必要がありませんでした。何がオリジナルに依存するのかわからない場合、デフォルトの引数を使用して他のプログラマーによって継承された関数を展開するだけだからです。答えに興味があります。
Kai Qing

3
久しぶりに見た中で最高の質問の1つです。何も渡さないでみましたか?foo("blah", , "test");
マダラのゴースト

2
ルールは、デフォルトの引数は引数の後にのみ続くことができるということです。つまり、foo( "blah")とx、yがデフォルトか、foo( "Blah"、 "xyz")とyがデフォルトです。
マウスフード

1
予想される行動。php.net/manual/en/functions.arguments.phpの「デフォルトの引数値」セクションを参照してください。null値と空の文字列は、関数への実際の引数として受け入れられます
jmdavalos

回答:


164

関数宣言を次のように変更して、必要な操作を実行できるようにすることをお勧めします。

function foo($blah, $x = null, $y = null) {
    if (null === $x) {
        $x = "some value";
    }

    if (null === $y) {
        $y = "some other value";
    }

    code here!

}

このように、foo('blah', null, 'non-default y value');2番目のパラメーターが$xまだデフォルト値を取得するように、呼び出しを希望どおりに実行できます。

このメソッドでは、null値を渡すことは、その後に続くパラメーターのデフォルト値をオーバーライドするときに、1つのパラメーターのデフォルト値が必要であることを意味します。

他の回答で述べたように、

デフォルトのパラメーターは、関数の最後の引数としてのみ機能します。関数定義でデフォルト値を宣言したい場合、1つのパラメーターを省略して、それに続くパラメーターをオーバーライドする方法はありません。

さまざまな数のパラメーターとさまざまな型のパラメーターを受け入れることができるメソッドがある場合、Ryan Pが示した答えと同様の関数を宣言することがよくあります。

ここに別の例があります(これはあなたの質問には答えませんが、情報提供があれば幸いです:

public function __construct($params = null)
{
    if ($params instanceof SOMETHING) {
        // single parameter, of object type SOMETHING
    } else if (is_string($params)) {
        // single argument given as string
    } else if (is_array($params)) {
        // params could be an array of properties like array('x' => 'x1', 'y' => 'y1')
    } else if (func_num_args() == 3) {
        $args = func_get_args();

        // 3 parameters passed
    } else if (func_num_args() == 5) {
        $args = func_get_args();
        // 5 parameters passed
    } else {
        throw new InvalidArgumentException("Could not figure out parameters!");
    }
}

なぜ$ x = isset($ x)ではないのですか?$ x: 'デフォルト値'; ?
zloctb 2015年

@zloctbこれは、クリーンで読み取り可能なnullチェックです。開発者の好みのようです。$ x = isset($ x)のどちらか?$ x: 'デフォルト値'; または$ x = is_null($ x)? 'default value':$ x; このソリューションと同様に機能します。これは、読みやすさとメンテナンスに関する好みの選択です。
DeveloperWeeks

9
将来の読者のために明確にするために。最初の解決策nullでは、毎回デフォルト値を割り当てるため、実際の値をパラメーターに割り当てることは明らかに不可能です。実際にnullが必要な場合に別の特別な値があった場合(たとえば、$ x == "use_null"が$ x = nullを作成した場合)でも、そのような特別な値をリテラル値として割り当てることはできません。パラメータ(この場合、 "use_null"文字列)。したがって、デフォルト値を使用したい(そしてnull有効なオプションにしたい)場合は、
必ず一意で不要

37

オプションの引数は、関数呼び出しの最後でのみ機能します。$ xを指定せずに関数で$ yの値を指定する方法はありません。一部の言語では、名前付きパラメーター(VB / C#など)を介してこれをサポートしていますが、PHPはサポートしていません。

引数ではなくパラメータに連想配列を使用する場合、これをエミュレートできます-つまり

function foo(array $args = array()) {
    $x = !isset($args['x']) ? 'default x value' : $args['x'];
    $y = !isset($args['y']) ? 'default y value' : $args['y'];

    ...
}

次に、次のように関数を呼び出します。

foo(array('y' => 'my value'));

1
isset($args['x'])空の文字列、空の配列、またはfalseデフォルト値で現在置き換えられるため、条件は実際にである必要があります。
Tim Cooper

@TimCooper笑私はあなたの最初のコメントに基づいて「=== null」でなければならないという変更に行き、代わりにissetを使用するように私の回答を変更しました。:D
Ryan P

ああ、ドラット!あんまり好きじゃない…。そのときは、デフォルトの引数の順序をもう少し考えなければならないでしょう。ありがとう!
レノーシス

残念ながら、この回答でnullを割り当てることはできません。これは良いオプションです: $x = !array_key_exists('x',$args) ? 'default x value' : $args['x'];
フランク・フォルテ

20

実際に可能です:

foo( 'blah', (new ReflectionFunction('foo'))->getParameters()[1]->getDefaultValue(), 'test');

あなたがそうしたいかどうかは別の話です:)


更新:

このソリューションを回避する理由は次のとおりです。

  • (間違いなく)醜い
  • 明らかにオーバーヘッドがあります。
  • 他の答えの証明として、代替案があります

ただし、実際には次のような状況で役立ちます。

  • 元の機能を変更したくない/変更できない。

  • あなたは機能を変更することができますが:

    • 使用null(または同等のもの)はオプションではありません(DiegoDDのコメントを参照)
    • あなたは連想と一緒に行くことも、一緒に行くこともしたくない func_num_args()
    • あなたの人生はいくつかのLOCを保存することに依存しています

パフォーマンスについては、非常に単純なテストで、Reflection APIを使用してデフォルトのパラメーターを取得すると、関数の呼び出しが25倍遅くなりますが1マイクロ秒未満しかかかりません。それと一緒に暮らせるかどうか知っておくべきです。

もちろん、ループで使用する場合は、事前にデフォルト値を取得しておく必要があります。


1
これを望まない理由は何ですか?かなり便利なようです。
ブライアン

10
function image(array $img)
{
    $defaults = array(
        'src'    => 'cow.png',
        'alt'    => 'milk factory',
        'height' => 100,
        'width'  => 50
    );

    $img = array_merge($defaults, $img);
    /* ... */
}

2
何か不足していますか?これは質問にまったく答えていないようですが、7つの賛成票があります。多分少しの説明を追加すると役立つでしょうか?
Sean the Bean

3
@SeantheBean:true、説明の方が良いでしょうが、彼の要点は次のとおりです。PHPには名前付き引数がないため、連想配列を単一のパラメーターとして使用します。
MestreLion 2018

1
質問の例を使用すると、さらに役立ちます。例:$defaults = [ 'x' => 'some value', 'y' => 'some other value'];
Frank Forte

4

それを行う唯一の方法は、パラメーターを省略することです。パラメーターを省略する唯一の方法は、パラメーターリストを再配置して、省略したいパラメーターが設定するパラメーターの後に来るようにすることです。例えば:

function foo($blah, $y = "some other value", $x = "some value")

次に、fooを次のように呼び出すことができます。

foo("blah", "test");

これは次の結果になります:

$blah = "blah";
$y = "test";
$x = "some value";

3

私は最近この問題を抱えており、この質問と回答を見つけました。上記の質問は機能しますが、問題は、それらをサポートするIDE(PHPStormなど)にデフォルト値が表示されないことです。

ここに画像の説明を入力してください

使用するnull場合、空白のままにすると値がどうなるかわかりません。

私が好む解決策は、関数定義にもデフォルト値を入れることです:

protected function baseItemQuery(BoolQuery $boolQuery, $limit=1000, $sort = [], $offset = 0, $remove_dead=true)
{
    if ($limit===null) $limit =1000;
    if ($sort===null) $sort = [];
    if ($offset===null) $offset = 0;
    ...

唯一の違いは、それらが同じであることを確認する必要があることです。


それ自体でReflectionFunctionを内部的に使用すると、コストを節約できます。
SubjectDelta

2

これを直接行うことはできませんが、少しコードをいじることでエミュレートできます。

function foo($blah, $x = false, $y = false) {
  if (!$x) $x = "some value";
  if (!$y) $y = "some other value";

  // code
}

6
これでうまくいきますがnull、この例では、概念的にはに比べてすっきりしていfalseます。
TRiG 2012

phpは厳密な言語ではないため、TriGのコメントに追加することfalseは、よりも危険な選択nullです。!$xプログラマを驚かせるかもしれない、いくつかの異なる入力に対してtrueになります: 0''。一方null、を使用する!issetと、より厳密なテストとして使用できます。
ToolmakerSteve

1
<?php
function info($name="George",$age=18) {
echo "$name is $age years old.<br>";
}
info();     // prints default values(number of values = 2)
info("Nick");   // changes first default argument from George to Nick
info("Mark",17);    // changes both default arguments' values

?>

1

null合体演算子を使用 した私の2セント??(PHP 7以降)

function foo($blah, $x = null, $y = null) {
    $varX = $x ?? 'Default value X';
    $varY = $y ?? 'Default value Y';
    // ...
}

あなたは私のrepl.itでより多くの例をチェックすることができます


0

これは、オブジェクトの方が優れている場合です。xとyを保持するようにオブジェクトを設定できるため、デフォルトを設定します。

配列によるアプローチはオブジェクトを作成するのに近いです(実際、オブジェクトはオブジェクトに対して機能するパラメータと関数の束であり、配列を取る関数はいくつかのovパラメータに対して機能します)

ひどくあなたはいつもいくつかのトリックをデフォルトとしてnullまたはこのようなものを設定することができます


0

次のように呼び出すことができるように、引数として空の文字列があるかどうかを確認することもできます。

foo('blah', "", 'non-default y value', null);

関数の下:

function foo($blah, $x = null, $y = null, $z = null) {
    if (null === $x || "" === $x) {
        $x = "some value";
    }

    if (null === $y || "" === $y) {
        $y = "some other value";
    }

    if (null === $z || "" === $z) {
        $z = "some other value";
    }

    code here!

}

nullまたはを入力してもかまいません""が、同じ結果が得られます。


0

個々のパラメーターではなく配列を関数に渡し、null結合演算子(PHP 7+)を使用します。

以下では、2つの項目を持つ配列を渡しています。関数内で、item1の値が設定されているかどうか、デフォルトのボールトが割り当てられていないかどうかを確認しています。

$args = ['item2' => 'item2',
        'item3' => 'value3'];

    function function_name ($args) {
        isset($args['item1']) ? $args['item1'] : 'default value';
    }

$args['item1'] = $args['item1']??'default value'; PHP 7以降で使用できます。$ argsを[ 'ITEM1']がnullの場合、default value文字列は$ argsを[ 'item1から']に割り当てられます
Sadee
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.