PHP by-reference参数和默认null

时间:2008-11-11 09:00:37

标签: php null pass-by-reference

假设我们有像

这样的方法签名
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传递给方法并依赖默认值之间有什么区别?这个约束是否写在手册中?它可以被规避吗?

6 个答案:

答案 0 :(得分:24)

这是因为你不能引用null。

您可以引用一个包含null的变量 - 这正是默认值所做的。或者你可以传入null作为文字值 - 但是因为你想要一个out参数,所以这里不可能。

答案 1 :(得分:10)

如果要显式传递NULL,则必须为by-ref参数创建虚拟变量,而不必在单独的行上创建该变量。您可以直接使用$ dummy = NULL之类的赋值表达式作为函数参数:

function foo (&$ref = NULL) {

    if (is_null($ref)) $ref="bar";
    echo "$ref\n";        
}

foo($dummy = NULL); //this works!

答案 2 :(得分:5)

我自己刚刚发现了这一点,而且我非常震惊o_O!

这是PHP documentation所说的:

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)返回"制作一杯卡布奇诺咖啡。"。 我使用的一种解决方法是在函数内部检查参数是否为null:

function makecoffee($type = null)
{
    if (is_null($type)){ 
       $type = "capuccino";
    }
    return "Making a cup of $type.\n";
}

现在makecoffee(null)返回"制作一杯卡布奇诺咖啡。"

(我意识到这并没有真正解决与Zend相关的问题,但它可能对某些人有用......)

答案 3 :(得分:4)

@ Tomalak

实际上,默认值会创建一个没有任何引用的变量。当你传递某些东西时,这是你无法开始的。

我发现的原因是以下示例(我没有测试):

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 但它没有,所以你必须使用虚拟变量。

答案 4 :(得分:1)

确认Tomalak陈述here

以下作品:

$k=array();
$v=null;
$dn=Zend_Ldap_Dn::explodeDn('CN=Alice Baker,CN=Users,DC=example,DC=com', $k, $v, 
    Zend_Ldap_Dn::ATTR_CASEFOLD_UPPER);

不好 - 但解释清楚易懂。

答案 5 :(得分:0)

正如@aschmecher在评论中指出的那样 @Szczepan's answer herefunc($var = null)会产生严格的标准声明。

一个解决方案

这是一种不会产生任何此类警告的方法:

<?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())的第二次调用是验证引用$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
);

其他注意事项

我担心的一件事是这种方法是否会造成内存泄漏。以下测试表明它没有:

<?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。