关于Notice:Indirect modification of overloaded property 的问题

今天在项目中给类对象赋值的时候,发现并没有成功,仔细排查代码并没有发现逻辑错误,由于历史原因代码有些地方写的不规范,于是打开调试开关,出现Notce:Indirect modification of overloaded property的提示,大量搜索之后,问题解决,也加深了对面向对象的理解。

  1. 父类A:
<?php
/**
 * Created by PhpStorm.
 * User: simple.top
 * Date: 2016/12/15
 * Link: http://simple.top
 */
abstract class A
{
    private $data = array();

    public function __set($name, $value)
    {
        $this->data[$name] = $value;
    }

    public function __get($name)
    {
        return $this->data[$name];
    }

}
  1. 子类B[代码严谨点,初始化属性vars]
class B extends A
{
    public $vars = array();
    public function run()
    {
        $data = array(
            0 => array(
                'title' =>'aa'
            ),
            1 => array(
                'title' => 'bb'
            )
        );
        $this->vars = $data;
        foreach ($this->vars as &$v) {
            $v['desc'] = rand(1,999);
        }
    }
}
//调用并打印
$obj = new B();
$obj->run();
print_r($obj->vars);

//结果与预期一致,没有报错
Array ( [0] => Array ( [title] => aa [desc] => 390 ) [1] => Array ( [title] => bb [desc] => 152 ) )
  1. 子类C【代码不严谨,未初始化属性vars- ==问题复现==】
class C extends A
{
    public function run()
    {
        $data = array(
            0 => array(
                'title' =>'aa'
            ),
            1 => array(
                'title' => 'bb'
            )
        );
        $this->vars = $data;
        foreach ($this->vars as &$v) {
            $v['desc'] = rand(1,999);
        }
    }
}
//调用并打印
$objC = new C();
$objC->run();
print_r($objC->vars);
//Notice: Indirect modification of overloaded property C::$vars has no effect in D:\xampp\htdocs\www\www.test.localhost\class\call.php on line 60
//此时出现Notice提示,并且desc索引并没有赋值成功
Array ( [0] => Array ( [title] => aa ) [1] => Array ( [title] => bb ) )
  1. 错误提示大意是,重载(zhong4,zai4)属性C::$vars时失败。此问题的解决方法就是把__get()魔术方法改成&__get(), 那么我们修改下父类A:
abstract class A
{
    private $data = array();

    public function __set($name, $value)
    {
        $this->data[$name] = $value;
    }

    public function &__get($name)
    {
        return $this->data[$name];
    }

}
//此时再执行下C类方法,结果与预期一致了,没有错误提示了。
  1. 总结:当类访问未定义或不可见的类属性性var时,会访问__get()方法,如果__get()返回的值不是引用传递的时候,那么对var的赋值操作就会失败。所以,为了避免此问题,要么初始化要赋值的属性,要么修改__get()方法,强制返回引用传递。当然,规范来讲,类的属性必须初始化,否则就可能出现无法预期的结果,平时要多注意哦~

参考文献:
https://bugs.php.net/bug.php?id=40625

标签: php, 面向对象, 魔术方法

添加新评论