PHP: 为什么只有变量可以按引用传递?

3
如果你是PHP开发人员,你很可能会看到以下通知:

注意:仅应通过引用传递变量在/somefile.php的第xxx行

(问题在Only variables should be passed by reference中被广泛讨论。)
举个例子,抛出这个通知:
$string = "hi-dude";
echo end(explode('-', $string));

工作示例:

$string = "hi-dude";
$strings = explode('-', $string);
echo end($strings);

解释:

只有真实的变量可以通过引用传递,而不能传递返回正确变量的函数。

然而,我想不出为什么会发生这个通知。它似乎是不必要的,有时需要我编写大量额外的代码。PHP为什么有这个奇怪的限制?为什么会存在这个问题?


1
因为end会影响内部指针,所以函数不返回引用,因此会出现该提示。 - Lawrence Cherone
如果你想要一行代码,可以使用 echo $v[array_key_last($v = explode('-', $string))]; ;p - Lawrence Cherone
@LawrenceCherone,我有时候看到你可以用一行代码搞定。我也知道它会影响内部指针,但是如果数组不再需要了,谁在乎呢?为什么他们还要为此发出通知? - Blackbam
& 表示按引用传递,如果您将函数作为参数传递给另一个函数,而该函数不返回引用,则任何函数都会抛出该通知。 如果您不想看到通知或不关心它,请使用 @ 来抑制它,但这是另一个问题。 - Lawrence Cherone
1
@RyanVincent 不是很有趣,它只是没有输出警告:https://eval.in/1053974 - Lawrence Cherone
显示剩余5条评论
2个回答

2

最后,我找到了一个很好的解释,帮助我理解这个问题:传递值和传递引用有什么区别?

正如Daniel Pryden所说:

简单来说:

  • 传值表示将值作为函数参数传递
  • 传引用表示将变量作为函数参数传递

用隐喻来说:

  • 传值就像我在一张纸上写下一些东西并把它递给你。也许这是一个URL,也许是《战争与和平》的完整副本。无论它是什么,它都在我递给你的一张纸上,因此现在它有效地成为了你的一张纸。你现在可以在那张纸上涂鸦,或者用那张纸去寻找其他地方的东西并搞乱它,随便你。
  • 传引用就像我给你我的笔记本,里面写着一些东西。你可以在我的笔记本上涂鸦(也许我想让你这样做,也许不想),之后我会保留我的笔记本,上面有你写下的任何涂鸦。另外,如果你或我在那里写的是关于如何找到其他地方某些信息的信息,则你或我可以去那个地方并搞乱那些信息。

在这种情况下,“只有变量应该通过引用传递”通知仍然无法证明,因为我们只对获取数组的最后一个值感兴趣。但是函数end()被定义为:

mixed end ( array &$array )

&符号表示通过引用传递的方式是有一定原因的:end()不仅仅返回数组的最后一个元素,还会将其内部指针改为最后一个元素。因此,这个数组被修改了。

如果我们只想返回数组的最后一个元素而不改动它,就不需要通过引用传递数组,也就不会得到这个通知。但是,end()似乎并不是做这件事的正确函数。

如果我得到这个通知没有理由怎么办?请注意,要调用的函数可能定义错误。在我的例子中,我定义了一个函数:

/**
 * Flatten an array by one level if only needing a certain key value from a sub array.
 *
 * Example: [["foo"=>"bar","foo"=>"cheese"]]
 * Result: ["bar","cheese"]
 *
 * @param $array: The input array.
 * @param $key: The key to flatupshift. Default is 0.
 * @return $array: The result
 */
private function array_flatupshift(&$array, $key = 0) {
    $a = [];
    foreach ($array as $item) {
        if (is_object($item)) {
            array_push($a, $item->$key);
        } else if (is_array($item)) {
            array_push($a, $item[$key]);
        }
    }
    return $a;
}

这只是一个错误的函数定义。因此,如果你也收到类似的通知:检查你调用的函数是否被正确定义。在这里传递引用没有意义,因为传递的数组没有被修改。因此函数定义应该不包含“reference &/”:

private function array_flatupshift($array, $key = 0) {

如果你知道自己在做什么,有些情况下你可能会使用错误控制运算符。因此:

$string = "hi-dude";
echo @end(explode('-', $string));

如果不再需要explode的结果,那么这应该是可以的。但是请注意抑制所有可能错误的缺点。如果我说错了,请纠正我。


是的,这是关键点:函数是否实际上修改了传递给它的变量,通过使用&符号,它表明它想要修改变量,因此如果您传递一个非变量,您就“违反”了该请求。 - IMSoP
1
值得注意的是,@ 运算符有时会对性能产生不利影响(因为 PHP 必须停止以切换错误处理程序,然后再次启用它,无法优化该行周围的代码,否则将会很好)。 - IMSoP

2

end()array_pop()会返回带有以下消息的E_NOTICE

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

原因是end()需要一个引用,因为它使当前元素指针指向最后一个元素。

您可以使用一行代码完成此操作,

$string = "this-is-a-sample-text";
echo substr(strrchr($string, '-'), 1);

DEMO: https://3v4l.org/jO29n


为什么这些函数会返回这个通知? - Blackbam
这是一个很大的进步,谢谢。在像这样当前元素指针指向哪里的情况下,为什么这很重要呢?如果我传递了一个返回数组的函数,那么数组指针在哪里并不重要,我只想要最后一个值并继续进行。 - Blackbam
我的英语不是很好,所以有点难为我来向你解释,但我认为这就是我想说的。https://dev59.com/3m445IYBdhLWcg3w6eXz#39277181 - A l w a y s S u n n y
真的很喜欢答案中的这句话:“你不能创建一个指向不存在东西(或者指向内存中未知的东西)的引用”。现在我想知道,如果传递了这个值,为什么他们不在内存中创建它,但那可能是另一个问题。 - Blackbam
@Blackbam 很高兴能在某种程度上帮到你。祝你好运 :) - A l w a y s S u n n y
最后,我完全理解了这里出了什么问题,并发布了另一个答案。尽管如此,还是感谢您的帮助+1。 - Blackbam

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