请帮助我了解此症状是PHP中的意外错误/不良优化/还是预期行为。
这里有一个小代码:
class Packet {
public $length;
public $time;
}
class Stream {
public $packets = array();
// Basically what I want is to make sure
// I put my packet in the array as reference
// because later in the code where I call this
// function, I change my Packet object's values
// and I want this change to appear in the
// $this->packets array. So I pass by reference.
// I don't want to copy the Packet object at all!
public function addPacket(&$packet){
$this->packets[] = &$packet; //note here the reference operator
}
}
...
foreach($packets as $packet){
$myPrettyStream->addPacket($packet);
}
所以我在代码注释中解释了我想做什么。我的问题是:在我将所有数据包添加到 foreach 中的流后,我的所有Stream::packets
数组元素都将包含(引用)我添加到流中的最后$packet
。
似乎 PHP 在函数调用之间保留了我的addPacket(&$packet)
函数中的$packet
变量。(这可能是有意的或糟糕的优化?无论我是否通过引用数组(基本上是引用引用 &$packet)或仅仅是$packet
(&$packet) 的引用来传递 &$packet
变量,我认为这不应该是预期的行为。
不过,如果我不在函数内进行引用,它可以工作:
public function addPacket(&$packet){
$this->packets[] = $packet;
}
请有人解释为什么这种行为是有意义的!
谢谢!
====
==================================================================================溶液
感谢您的正确答案,我模拟了一个行为相同的函数调用:
// try to emulate function call inside iteration
$packet = $packets[0];
$functionPacket = &$packet;
$packetsItem[0] = &$functionPacket; //functionpacket holds a reference to $packet
var_dump($packetsItem);
echo "'nsecond iteration'n";
unset($functionPacket);
$packet = $packets[1];
$functionPacket = &$packet;
$packetsItem[1] = &$functionPacket;
var_dump($packetsItem);
output:
array(1) {
[0]=>
&object(Packet)#1 (2) {
["time"]=>
int(1)
}
}
array(2) {
[0]=>
&object(Packet)#2 (2) {
["time"]=>
int(2)
}
[1]=>
&object(Packet)#2 (2) {
["time"]=>
int(2)
}
}
PHP 总是通过引用传递对象,因此绝对不需要&
,在您的情况下,它甚至是有害的(正如您已经意识到的那样;))。
问题是,你"引用引用"而不是对象。这意味着,数组中的每个项都是对方法内部$packet
的引用,这本身就是对数组外部$packet
的引用。现在,当您更改$packet
(foreach
-循环)时,数组中的每个项目似乎都会更改,但实际上它们与以前保持相同的引用。
根据经验:如果你需要&
除out
参数之外的所有内容,你应该考虑你的设计。如果你需要out
参数,那么你也应该考虑一下。通常(不再需要)这样做,它使许多事情(不必要的)变得复杂。特别是:切勿使用&
进行微优化。
你可以想象,它看起来像这样(即使它可能不是那么准确)
// First iteration
$packet --> $packets[0]
// Pass to method
Stream::addPackage():$packet --> $packet --> $packets[0]
// Assign to array
Stream::$packets[0] --> Stream::addPackage():$packet --> $packet --> $packets[0]
// Second iteration (!)
Stream::$packets[0] --> Stream::addPackage():$packet --> $packet --> $packets[1]
请注意,Stream::$packets[0]
现在如何"指向"$packets[1]
http://www.php.net/manual/en/language.references.pass.php
通过引用传递变量时,只需在函数声明中添加 &。 在函数中,您无需在变量名称前面添加 &。
public function addPacket(&$packet){
$this->packets[] = &$packet; // should be $this->packets[] = $packet;
}