PHP 按引用参数和默认 null

PHP by-reference parameters and default null

提问人:Stefan Gehrig 提问时间:11/11/2008 最后编辑:Benjamin GruenbaumStefan Gehrig 更新时间:1/28/2015 访问量:17728

问:

假设我们有一个方法签名,例如

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

php null 按引用传递

评论


答:

29赞 Tomalak 11/11/2008 #1

这是因为你不能引用 null。

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

1赞 Stefan Gehrig 11/11/2008 #2

只是为了确认 Tomalak 在这里所说的话:

以下作品:

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

不好 - 但解释清晰易懂。

4赞 josh 9/3/2010 #3

@托马拉克

实际上,默认值创建一个不涉及任何引用的变量。这是你在传递东西时根本无法踢的东西。

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

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应该提供一种不传递某些参数的方法,例如使用
或类似的语法,而不是传递NULL。
但事实并非如此,因此您必须使用虚拟变量。
foo($p1, , , $p4);

评论

0赞 Chris Middleton 9/17/2014
这是一个有趣的语法想法......就我个人而言,我希望看到在调用中放置命名函数参数的能力,例如.doSomething($var1, @optionalParam4=$var2);
6赞 Rafa 11/20/2010 #4

我自己才发现这一点,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."

我本来希望回来“做一杯卡布奇诺”。 我使用的一种解决方法是在函数内部检查参数是否为 null:makecoffee(null)

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

现在返回“制作一杯卡布奇诺”。makecoffee(null)

(我意识到这实际上并不能解决与 Zend 相关的问题,但它可能对某些人有用......

11赞 Szczepan Hołyszewski 3/15/2012 #5

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

function foo (&$ref = NULL) {

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

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

评论

7赞 asmecher 1/10/2013
这给了我严格的模式警告:PHP Strict Standards: Only variables should be passed by reference in (snip)/test.php on line 9
0赞 Chris Middleton 1/28/2015
如果该变量尚不存在,那么当您像这样传入它时,它将为 null: .如果你想重用这个变量,并且想要一个单行代码,你总是可以 a) 确保它不会从函数中的 null 更改,或者 b) 这样做: .$dummyfoo($dummy)dummy($dummy = null) and foo($dummy)
1赞 Chris Middleton 1/28/2015 #6

正如@aschmecher在对@Szczepan的回答的评论中指出的那样,这样做会产生严格的标准通知。func($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。