只有变量可以通过引用传递

19

我曾经想到使用自定义的错误处理程序,结果却陷入了一个死胡同。

以下代码会出现这个错误(无论是否使用自定义错误处理程序): Fatal error: Only variables can be passed by reference

function foo(){
    $b=array_pop(array("a","b","c"));
    return $b;
}
print_r(foo());

以下代码仅在使用自定义错误处理程序时发生 (2048) Only variables should be passed by reference

function foo(){
    $a=explode( '/' , 'a/b/c');
    $c=array_pop(array_slice($a,-2,1));
    return $c;
}
print_r(foo());
第二个让我担心,因为我有很多“简略”的代码。所以,要么放弃使用自定义错误处理程序的好主意(以改进我的日志记录模块),要么扩展所有代码。
有更好的想法吗?还有,怎么回事?
更新:
感谢答案,我学到了一些关于php如何处理错误的知识。E_ALL不包括E_STRICT(php 5)的混乱不太好。
除此之外,创建自己的自定义错误处理程序默认启用E_STRICT,这就是问题的根源。
故事的寓意是使用自己的错误处理程序来捕获所有错误,并使用错误常量(E_STRICT、E_USER_WARNING、E_USER_ERROR等)来进行过滤。
至于与变量引用和某些函数相关的“内存损坏问题”,我能说什么呢?双倍的不酷。在我的错误处理程序中忽略E_STRICT(这并不意味着你应该这样做),生活依然继续。

$b=current(array_reverse(array("a","b","c"))); // 是的,它很傻,但它能用 :) - MSpreij
8个回答

20

array_pop() 试图更改作为参数传递的值。现在在您的第二个示例中,这是从 array_slice() 返回的值。在引擎术语中,这是一个“临时值”,这样的值不能通过引用传递。您需要一个临时变量:

function foo(){
    $a=explode( '/' , 'a/b/c');
    $b=array_slice($a,-2,1);
    $c=array_pop($b);
    return $c;
}
print_r(foo());

然后可以将对$b的引用传递给array_pop()函数。有关引用的更多详细信息,请参阅http://php.net/references


10

在将error_reporting设置为E_ALL | E_STRICT之后,在php-cli中尝试您的第二个php代码片段,我得到了以下结果:

    gparis@techosaure:~/workspace/universcine.com$ php -a
Interactive shell

php > function foo(){
php {     $a=explode( '/' , 'a/b/c');
php {     $c=array_pop(array_slice($a,-2,1));
php {     return $c;
php { }
php > print_r(foo());
PHP Strict standards:  Only variables should be passed by reference in php shell code on line 3
PHP Stack trace:
PHP   1. {main}() php shell code:0
PHP   2. foo() php shell code:1

正如您所看到的,这里只有严格的标准。您可以轻松地让自定义错误处理程序忽略它们(基于您获得的值:例如2048)。

从php 5.3开始,E_ALL不再包括E_STRICT,请看这个:

php > foreach(array("E_ALL", "E_DEPRECATED", "E_STRICT", "E_NOTICE", "E_PARSE", "E_WARNING") as $const) echo $const . "  :\t" . constant($const) ."\t". decbin(constant($const)). "\n";
E_ALL  :        30719   111011111111111
E_DEPRECATED  : 8192     10000000000000
E_STRICT  :     2048       100000000000
E_NOTICE  :     8                  1000
E_PARSE  :      4                   100
E_WARNING  :    2                    10

自php 5.4版本起,E_ALL包含E_STRICT
E_ALL  :            32767   111111111111111
E_DEPRECATED  :     8192     10000000000000
E_STRICT  :         2048       100000000000
E_NOTICE  :         8                  1000
E_PARSE  :          4                   100
E_WARNING  :        2                    10

不,它并没有。我编辑了我的帖子,添加了一个解释性的代码片段。看到 E_ALL 中缺少的 1 了吗?如果你加上 E_STRICT,你就会得到 111111111111111!意味着中了大奖! - greg0ire
实际上,E_STRICT从PHP 5.4开始包含在E_ALL中(正如链接的问题中现在所述)-请参阅PHP手册:http://www.php.net/manual/en/errorfunc.constants.php - 然而,w3schools.com仍然错误地报告说它只包括在PHP 6中。 - MrWhite
@w3d:你说得对,我更新了我的答案,如果你发现错误,请随意更正。 - greg0ire
如果二进制数字的单位列对齐,即右对齐,可能会更容易理解。 - Jason
@Jason,很好的发现,已经修复了。 - greg0ire
显示剩余2条评论

5

这是一个内存损坏问题(根据PHP开发团队)。只需添加一个赋值语句:

function foo(){
    $b = array_pop($arr = array("a","b","c"));
    return $b;
}
print_r(foo());

:

function foo(){
    $a = explode( '/' , 'a/b/c');
    $c = array_pop($arr = array_slice($a,-2,1));
    return $c;
}
print_r(foo());

第二个会产生一个 E_STRICT 错误。如果您希望在错误处理程序中以不同的方式处理它(如果您不想更改这些函数),则可以进行处理。

我在某个地方看到过这个技巧。这适用于所有函数还是某些函数? - zaf
你可以在任何函数中抛出赋值,但不可以在像empty这样的语言结构中抛出。 - webbiedave
这严重影响了我的功夫水平。 - zaf
在参数列表中的赋值是未定义行为。使用array_pop($arr = array("a","b","c"))时,不清楚哪个会先执行 - $arr = array("a","b","c")还是array_pop($arr)或array_pop(array("a","b","c"));并且这可能会在所有版本之间发生变化。 - johannes
@johannes: 你为什么这么说? - webbiedave
@johannes:不完全是这样。赋值表达式的值是被赋的值。因此,array_pop 操作的是赋值语句的返回值,该返回值必须在函数应用之前进行评估。 - voetsjoeba

2
< p >array_pop() 函数会改变传递给它的值,这就是错误的根源所在。一个函数是无法被更改的。换句话说,你需要先将数组赋值给一个变量(参考:手册),然后再运行 array_pop()

你需要的代码如下:

function foo(){
    $a = array("a","b","c");
    $b = array_pop($a);
    return $b;
}
编辑:你提到的两个函数都有同样的问题。将数组赋值给一个变量,然后将该变量传递给array_pop()

2

我认为现在(自 PHP 5 开始)应该这样写:

function &foo(){ //NOTICE THE &
    $b=array_pop(array("a","b","c"));
    return $b;
}
print_r(foo());

并且

function &foo(){ //NOTICE THE &
    $a=explode( '/' , 'a/b/c');
    $c=array_pop(array_slice($a, $b = -2, $c = 1)); //NOW NO DIRECT VALUES ARE PASSED IT MUST BE VARIABLES
    return $c;
}
print_r(foo());

但我只是一个初学者 :)

谢谢回答。我没有时间尝试,但是您的意思是添加'&'可以使其工作吗?它是做什么的?我明天会再看一下。 - zaf

1

试试这个:

function foo(){
    $a = array("a","b","c");
    $b = array_pop($a);
    return $b;
}

1

我刚刚在链式方法中遇到了这个错误。

doSomething()->andThis()

我有:

doSomething()-andThis() // missing `>` character

我的情境略微复杂,但它源于意外的 减法 操作。



网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接