Php:$var和&$var有什么区别?

24

什么是它们的区别?

foreach ($my_array as $my_value) {
}

而且:

foreach ($my_array as &$my_value) {
}

可以请您给我两个实际应用场景,说明何时使用其中一个,何时使用另一个吗?


3
一般来说,不要使用参考资料作为准则。 - troelskn
6
那是一个愚蠢的经验法则。有时候你必须要使用它们。如果你不知道是否应该使用它们,那么你可能不需要使用。但每当你想修改实际值时,你就必须使用引用。 - Felix Kling
1
@Felix Kling:我同意@troelskn的观点。我从来没有需要修改数组的实际值。每次我需要这样做时,你可以写出比使用('&$var')更好的代码。我能想到的唯一方法可能是……优化:如果你使用'&',我认为(如果我错了请纠正我)就不需要将其复制到临时变量中。因此可以节省执行时间。如果你有一个无法避免像我问题中带有'&'的循环的例子,我可以请你在评论中展示吗?非常感谢! - Olivier Pons
3
我的观点是,如果你需要参考来完成想做的事情,那么你做错了。应该重构你的代码。 - troelskn
@troelskn:当然有适当的时候可以使用引用。你知道对象引用(标识符)被传递到函数中吗?或者你是在每次传递之前克隆它们吗? ;) @Olivier Pons:PHP采用写时复制技术,因此如果您不修改变量,则通过引用传递不会节省时间。 - webbiedave
显示剩余2条评论
5个回答

31
第一个例子创建了一个值的副本,而第二个例子使用了对原始值的引用。所以在第一个foreach运行之后,原始数组仍然保持不变。而在第二个foreach之后,原始数组可能已经被修改,因为它是通过引用处理的。
一些原生的PHP函数已经以这种方式工作,比如shuffle(),它重新排列了数组的内容。你会注意到,这个函数不返回一个数组,你只需要调用它即可。
$myArray = array('foo', 'bar', 'fizz', 'buzz');
shuffle( $myArray );
// $myArray is now shuffled

它发挥了它的魔力,因为它通过引用而不是创建副本来处理数组。
然后还有一些函数不通过引用传递任何东西,而是处理原始值的副本,比如ucwords(),它返回新的结果字符串:
$myString = "hello world";
$myString = ucwords( $myString );
// $myString is now capitalized

看看按引用传递

2
如果$my_value是一个对象,那么无疑它是通过引用传递的。 - Epharion
1
@Epharion:不,PHP总是按值传递,除非告诉它按引用传递。对象也不例外。只有对于对象,由于PHP存储对象的方式,按值传递执行起来非常类似于按引用传递。 - NikiC

8

Jonathan的回答非常清楚地描述了它。为了完整起见,以下是您的两个示例:

  1. Just reading values:

    $my_array = range(0,3);
    foreach ($my_array as $my_value) {
        echo $my_value . PHP_EOL;
    }
    
  2. Adding some number to each element (thus modifying each value):

    foreach ($my_array as &$my_value) {
        $my_value += 42;
    }
    

    If you don't use &$my_value, then the addition won't have any effect on $my_array. But you could write the same not using references:

    foreach($my_array as $key=>$value) {
        $my_array[$key] = $value + 42;
    }
    

    The difference is that we are accessing/changing the original value directly with $my_array[$key].

DEMO


0
一个实际的应用场景是当你需要用很少的代码更改数组的内容时。
foreach($arrFeed as &$objFeed)
  $objFeed['externalSrc'] = convertToLocalImage($objFeed['externalSrc']);

0

当您在变量前加上“&”时,您正在创建一个“引用”。 PHP引用就像计算机上的快捷方式或符号链接。您可以创建一个指针变量,它只是相同数据的另一个名称。

我没有看到使用这些的很大区别,除了不复制变量以节省内存。当您传递变量时,您可以只传递引用,而引用指向原始对象。


一个典型的初学者错误:认为PHP很愚蠢。PHP并不是盲目地复制值。它使用写时复制的概念,即只有在值改变时才会被复制。出于性能原因创建引用通常只会适得其反,因为它经常导致PHP进行更多的复制。 - NikiC

0

我只在读取CSV文件时需要使用引用来知道分隔符是什么。只需取第一行:

$handle = fopen($file, "r");
$firstLine = fgets($handle);
fclose($handle);

然后使用这些可能的分隔符

$delimiters = array(';' => 0,',' => 0,"\t" => 0,"|" => 0);

按引用计数,找出最常用的

foreach ($delimiters as $delimiter => &$count) {
    $count = count(str_getcsv($firstLine, $delimiter));
}
$delimiter =  array_search(max($delimiters), $delimiters);

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