PHP参照パラメータとデフォルトのnull
-
07-07-2019 - |
質問
次のようなメソッドシグネチャがあるとします
public static function explodeDn($dn, array &$keys = null, array &$vals = null,
$caseFold = self::ATTR_CASEFOLD_NONE)
$ dn
の後のすべてのパラメーターを省略することで、メソッドを簡単に呼び出すことができます:
$dn=Zend_Ldap_Dn::explodeDn('CN=Alice Baker,CN=Users,DC=example,DC=com');
3つのパラメーターでメソッドを呼び出すこともできます:
$dn=Zend_Ldap_Dn::explodeDn('CN=Alice Baker,CN=Users,DC=example,DC=com', $k, $v);
および4つのパラメーター:
$dn=Zend_Ldap_Dn::explodeDn('CN=Alice Baker,CN=Users,DC=example,DC=com', $k, $v,
Zend_Ldap_Dn::ATTR_CASEFOLD_UPPER);
しかし、たとえば次のパラメーターの組み合わせでメソッドを呼び出すことができないのはなぜですか:
$dn=Zend_Ldap_Dn::explodeDn('CN=Alice Baker,CN=Users,DC=example,DC=com', $k, null,
Zend_Ldap_Dn::ATTR_CASEFOLD_UPPER);
$dn=Zend_Ldap_Dn::explodeDn('CN=Alice Baker,CN=Users,DC=example,DC=com', null, $v);
null
をメソッドに渡すこととデフォルト値に依存することの違いは何ですか?この制約はマニュアルに書かれていますか?回避できますか?
解決
nullへの参照を取得できないためです。
nullを含む変数への参照を持つことができます-これがまさにデフォルト値の動作です。または、リテラル値としてnullを渡すこともできますが、outパラメーターが必要なため、ここでは不可能です。
他のヒント
NULLを明示的に渡したい場合は、by-ref引数のダミー変数を作成する必要がありますが、その変数を別の行に作成する必要はありません。関数引数として$ dummy = NULLのような代入式を直接使用できます:
function foo (&$ref = NULL) {
if (is_null($ref)) $ref="bar";
echo "$ref\n";
}
foo($dummy = NULL); //this works!
自分でこれを見つけたばかりで、ショックを受けましたo_O!
これは PHPのドキュメント言う:
function makecoffee($type = "cappuccino")
{
return "Making a cup of $type.\n";
}
echo makecoffee(); // returns "Making a cup of cappuccino."
echo makecoffee(null); // returns "Making a cup of ."
echo makecoffee("espresso"); // returns "Making a cup of espresso."
makecoffee(null)
が「Mapping a cup of cappuccino。」を返すと予想していました。
私が使用した回避策の1つは、引数がnullかどうかを関数内で確認することです。
function makecoffee($type = null)
{
if (is_null($type)){
$type = "capuccino";
}
return "Making a cup of $type.\n";
}
Now makecoffee(null)
は、「Make a cup of cappuccino」を返します。
(これは実際にはZend関連の問題を解決するものではないが、一部の人にとっては役立つかもしれない...)
@トマラック
実際には、デフォルト値は、参照を伴わない変数を作成します。これは、何かを渡すときに簡単に開始できないものです。
理由を説明するために見つけたのは、次の例です(テストしませんでした):
function foo (&$ref = NULL) {
$args = func_get_args();
echo var_export($ref, TRUE).' - '.var_export($args, TRUE);
}
$bar = NULL;
foo(); // NULL - array()
foo($bar); // NULL - array(0 => NULL)
私の意見では、PHPは、
のように、特定のパラメーターを渡さない方法を提供すべきです。
foo($ p1、、、$ p4);
またはNULLを渡す代わりの同様の構文。
しかし、そうではないので、ダミー変数を使用する必要があります。
@aschmecherがコメントで指摘したように
@Szczepanの答えはこちら、 func($ var = null)
を実行すると、厳格な標準通知が生成されます。
1つのソリューション
このような警告を生成しないメソッドは次のとおりです。
<?php
error_reporting(E_ALL | E_STRICT);
function doIt(&$x = null) {
if($x !== null) echo "x not null: $x\n";
$x = 2;
}
function &dummyRef() {
$dummyRef = null;
return $dummyRef;
}
doIt(dummyRef());
doIt(dummyRef());
説明
変数を渡す代わりに、参照を返す関数の結果を渡します。 doIt(dummy())
の2番目の呼び出しは、参照 $ dummy
値が呼び出し間で保持されないことを確認することです。これは、変数を明示的に作成することとは対照的です。変数を累積値をクリアすることを忘れないでください。
$dummyRef = null;
doIt($dummyRef);
doIt($dummyRef); // second call would print 'x not null: 2'
アプリケーション
OPの例では、次のようになります。
$dn = Zend_Ldap_Dn::explodeDn(
'CN=Alice Baker,CN=Users,DC=example,DC=com',
$k,
dummyRef(),
Zend_Ldap_Dn::ATTR_CASEFOLD_UPPER
);
追加の考慮事項
私が心配するかもしれないことの1つは、このメソッドがメモリリークを引き起こすかどうかです。次のテストは、そうではないことを示しています。
<?php
function doItObj(&$x = null) {
if(gettype($x) !== "object") echo "x not null: $x\n";
$x = 2;
}
function &dummyObjRef() {
$dummyObjRef = new StdClass();
return $dummyObjRef;
}
echo "memory before: " . memory_get_usage(true) . "\n";
for($i = 0; $i < 1000000; $i++) {
doItObj(dummyObjRef());
}
echo "memory after: " . memory_get_usage(true) . "\n";
echo "\n$i\n";
私のシステム(PHP 5.6.4を使用)では、memory_get_usageの両方の呼び出しで〜262 KBが表示されました。