web-dev-qa-db-ja.com

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

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");   

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

156
renosis

あなたがしたいことができるように、関数宣言を次のように変更することを提案します:

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!");
    }
}
146
drew010

オプションの引数は、関数呼び出しの最後でのみ機能します。関数で$ 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'));
35
Ryan P

実際に可能です:

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

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


更新:

この解決策を避ける理由は次のとおりです。

  • それは(おそらく)いです
  • 明らかなオーバーヘッドがあります。
  • 他の答えの証明として、代替手段があります

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

  • 元の機能を必要としない/変更できない。
  • あなたは機能を変更することができますが:

    • null(または同等のもの)を使用することはオプションではありません(DiegoDDの comment を参照)
    • 連想型でもfunc_num_args()でも使いたくない
    • あなたの人生はいくつかのLOCを保存することにかかっています

パフォーマンスについては、 非常に簡単なテスト は、Reflection APIを使用してデフォルトのパラメーターを取得すると、関数呼び出しが25倍遅くなることを示しています1マイクロ秒未満。あなたはそれで生きることができるかどうかを知る必要があります。

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

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

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

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

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

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

foo("blah", "test");

これにより、次の結果が得られます。

$blah = "blah";
$y = "test";
$x = "some value";
3
Wes Crow

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

enter image description here

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;
    ...

唯一の違いは、それらが同じであることを確認する必要があるということです-しかし、それは追加の明確さのために払うには小さな代償だと思います。

2
Yehosef

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

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

  // code
}
2
kba
<?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
Odin

個々のパラメーターの代わりに配列を関数に渡し、null合体演算子を使用します(PHP 7以降)。

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

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

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

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

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

通常、nullまたはこのようなものをデフォルトとして設定するために、いくつかのトリックをいつでも実行できます。

0
SergeS

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

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
Mustafa Ekici