1

この症状が意図しないエラーか、不適切な最適化か、または 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に、ストリームに追加した LAST への (参照) が含まれることです。

PHP は、関数呼び出し間で関数$packet内の変数を保持しているようです。(これは意図されたものか、最適化が間違っている可能性がありますか?)配列への参照 (基本的に参照参照 &&$packet) または単に (&$packet) の参照によって変数addPacket(&$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)
  }
}
4

2 に答える 2

3

PHPは常にオブジェクトを参照渡しするため、その必要はまったくなく&、あなたの場合、それは有害ですらあります(すでに気づいているように;))。

問題は、オブジェクトではなく「参照を参照する」ことです。これは、配列内のすべての項目が$packetメソッド内からの参照であり、それ自体が配列$packetからの参照であることを意味します。変更すると( -loop)、配列内のすべての項目が変更されるように見えますが、実際には以前と同じ参照のままです。$packetforeach

経験則として: -arguments&以外のすべてが必要な場合は、設計を検討する必要があります。-argumentsが必要な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]

于 2012-04-06T14:35:23.583 に答える
1

http://www.php.net/manual/en/language.references.pass.php

参照によって変数を渡す場合、関数宣言に&を追加するだけで済みます。関数内で、変数名の前に&を追加する必要はありません。

public function addPacket(&$packet){
    $this->packets[] = &$packet; //  should be $this->packets[] = $packet;
}
于 2012-04-06T14:08:26.383 に答える