这个PHP代码会发生什么样的魔法?

时间:2017-08-22 07:50:07

标签: php reference getter-setter

任何知道php内幕的人都能解释一下这样的PHP行为吗?

<?php

class Test {

     private $a;

     public function __get($name) {
       echo('GETTER CALLED!');
       return null;
     }

     public function testme() {
       $v = array(1, 2, 3);
       unset($this->a); // <-- this line *
       $this->a = &$v;
     }

 }

 $test = new Test();
 $test->testme();

unset($this->a)在这里(即没有注释掉)时,php导致以下输出错误:

GETTER CALLED!<br />
<b>Notice</b>:  Indirect modification of overloaded property Test::$a has no effect in <b>[...][...]</b> on line <b>15</b><br />
<br />
<b>Fatal error</b>:  Uncaught Error: Cannot assign by reference to overloaded object in [...][...]:15
Stack trace:
#0 [...][...](21): Test-&gt;testme()
#1 {main}
  thrown in <b>[...][...]</b> on line <b>15</b><br />

但是评论出这条线似乎解决了问题所以原因是什么? 真正的问题是:

  1. &#34;间接修改超载财产&#34;发生了什么?

  2. &#34;无法通过引用分配重载对象&#34; - 为什么只能在unset之后?

  3. 为什么要调用吸气剂?虽然它没有。但

4 个答案:

答案 0 :(得分:0)

http://php.net/manual/en/language.oop5.overloading.phphttp://php.net/manual/en/language.oop5.magic.php

  

PHP中的重载提供了动态“创建”属性和方法的方法。这些动态实体通过魔术方法处理,可以在类中为各种动作类型建立。

当您取消设置()私有变量$ a时,就好像它从未存在过一样,就好像你从未设置“private $ a;”在课程开始时。在第16行,PHP注意到$ this-&gt; a没有设置,并且使用__get方法启动了魔法。您开始使用重载属性$ this-&gt; a“神奇地”创建。

所以回答你的问题:

  1. 在__get()方法中,如果我没弄错的话。
  2. 只有在你使用unset()之后,因为在你的类顶部定义的私有$ a被使用,直到你实际取消它()它。
  3. 应调用它,因为如果未设置类属性并且通过引用进行设置,则调用__get()是PHP的正常行为。您将使用以下简化示例获得相同的结果:
  4. <?php
    
    class Test {
        public function __get($name) {
            echo('GETTER CALLED!');
            return null;
        }
    
        public function testme() {
            $v = array(1, 2, 3);
            $this->a = &$v;
        }
    }
    
    $test = new Test();
    $test->testme();
    

答案 1 :(得分:0)

魔法方法__get的参数不能通过引用传递。

更简单的代码:

class Test {
     public function __get($name) {
       return null;
     }
 }

 $test = new Test();
 $a=1;
 $test->a=&$a; # <-- Cannot assign by reference to overloaded object

请参阅:http://php.net/manual/en/language.oop5.overloading.php

答案 2 :(得分:0)

从DoPPeS的解释来看,我的工作变化很小。我在类外部移动了数组的创建,并添加了一个getter,以验证引用的赋值是否正常工作。

简单的解决方法是,从DoPPeS所说的,它必须重新创建属性,但不能直接分配引用,首先使用虚拟值来创建属性,它现在存在并且可以通过引用分配(那里)可能是更优雅的解决方案,但它的工作原理):

<?php

class Test {

    private $a;

    public function __get($name) {
        echo('GETTER CALLED!');
        return null;
    }

    public function testme(&$val) {
        unset($this->a);
        $this->a = 'test'; // <-- creates the property
        $this->a = &$val; // <-- now reference works
    }

    public function getVal($name) {
        if(!isset($this->{$name})){
            return NULL;
        }
        return $this->{$name};
    }

}

$v = array(1, 2, 3);
$test = new Test();
$test->testme($v);
$v[] = 4;
var_dump($test->getVal('a'));

?>

答案 3 :(得分:0)

最后一个问题非常有趣,我通过搜索获得以下信息,希望对您有所帮助。

  1. 在取消设置属性后,该属性将不存在,因此&#34; $ this-&gt; a&#34;是&#34;重载&#34;。
  2.   

    这些魔术方法的参数可以通过引用传递。 PHP Manual

  3.   

    这个功能最初对我来说看起来像个错误,但在询问了很多之后,结果却是预期的行为。 Regression/unset properties behavior