2013年11月19日 星期二

[PHP] Call By Reference 的陷阱

class ClassA
{
   private $fields;

   public function test1()
   {
      $this->fields = array(1,2,3);
      foreach ($this->fields as &$v) {
          $v += 1;
      }
                
      $localFields = array('x','y','z');
      foreach ($localFields as $v) {
      }
      echo json_encode($this->fields); // expect: [2,3,4], output: [2,3,"z"]
   }
                
   public function test2()
   {
      $this->fields = array(1,2,3);
      foreach ($this->fields as &$v) {
          $v += 1;
      }

      $v = 'abc';
      echo json_encode($this->fields); // expect: [2,3,4], output: [2,3,"abc"]
   }
                
   public function test3()
   {
      $this->fields = array(1,2,3);
      foreach ($this->fields as &$v) {
          $v += 1;
      }

      $this->inner();
   }

   private function inner()
   {
      $v = '***';
      echo json_encode($this->fields); // output: [2,3,4]
   }
}

$obj = new ClassA();
$obj->test1();
$obj->test2();
$obj->test3();

上面可以看到,雖然第一次使用 &$v 是在迴圈中,第二次使用 $v是在另一個迴圈。 原本預想應該是互不相關,但是顯然 Call By Reference 影響到第一次使用的欄位,造成出乎意料的狀況。


解決的方法:使用完 &$v 之後就馬上 unset($v); 缺點是可能會看不懂為什麼這樣做。

比較好的作法還是改用索引存取:

foreach ($this->fields as $k => $v) {
    $this->fields[$k] = $v + 1;
}

PHP 5.3.24 (cli) (built: Jun 10 2013 16:42:20)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2013 Zend Technologies
    with Xdebug v2.2.0rc1, Copyright (c) 2002-2012, by Derick Rethans

[Java] Invalid HTTP method: PATCH

最近系統需要使用 Netty4,所以把衝突的 Netty3 拆掉,然後就出現了例外。 pom.xml <dependency> <groupId>com.ning</groupId> <artifactId>as...