PHP - 间接修改重载属性

w00*_*w00 53 php magic-methods

我知道这个问题已被问过好几次了,但是他们都没有一个真正的答案来解决这个问题.也许有一个针对我的具体案例.

我正在构建一个mapper类,它使用magic方法__get()来延迟加载其他对象.它看起来像这样:

public function __get ( $index )
{
    if ( isset ($this->vars[$index]) )
    {
        return $this->vars[$index];
    }

    // $index = 'role';
    $obj = $this->createNewObject ( $index );

    return $obj;
}
Run Code Online (Sandbox Code Playgroud)

在我的代码中我做:

$user = createObject('user');
$user->role->rolename;
Run Code Online (Sandbox Code Playgroud)

这项工作到目前为止.该User对象没有名为"role"的属性,因此它使用magic __get()方法创建该对象,并从"role"对象返回其属性.

但是当我尝试修改'rolename'时:

$user = createUser();
$user->role->rolename = 'Test';
Run Code Online (Sandbox Code Playgroud)

然后它给我以下错误:

注意:间接修改重载属性无效

不确定这是否仍然是PHP中的一些错误,或者它是否是"预期的行为",但无论如何它都不能按我想要的方式工作.这对我来说真的是一个阻止......因为我怎么能改变延迟加载对象的属性?


编辑:

当我返回包含多个对象的数组时,似乎只会发生实际问题.

我添加了一个代码片段来重现问题:

http://codepad.org/T1iPZm9t

你真的应该在你的PHP环境中运行它,真正看到'错误'.但这里有一些非常有趣的东西.

我试图改变一个对象的属性,这给了我通知'不能改变重载属性'.但是,如果我在之后回复该属性,我发现它实际上是DID改变了价值......真的很奇怪......

Vin*_*nyD 91

您需要做的就是在__get函数前添加"&"以将其作为参考传递:

public function &__get ( $index )
Run Code Online (Sandbox Code Playgroud)

挣扎了一段时间.

  • 它导致函数通过引用而不是值返回 - 这意味着您可以更新属性的值.如果它只是按值返回(即没有&符号),则对该值所做的任何更改都不会存储在属性中. (5认同)
  • 任何人都可以帮助解释为什么这有效吗?变量或函数之前的&符号甚至是什么? (3认同)
  • 这是我期待的最期待的答案! (3认同)
  • 这有效,但您不能再抛出异常并返回 NULL 或 false 值。仅通过引用值。 (2认同)

Bab*_*aba 16

很高兴你给了我一些可以玩的东西

class Sample extends Creator {

}

$a = new Sample ();
$a->role->rolename = 'test';
echo  $a->role->rolename , PHP_EOL;
$a->role->rolename->am->love->php = 'w00';
echo  $a->role->rolename  , PHP_EOL;
echo  $a->role->rolename->am->love->php   , PHP_EOL;
Run Code Online (Sandbox Code Playgroud)

产量

test
test
w00
Run Code Online (Sandbox Code Playgroud)

使用的类

abstract class Creator {
    public function __get($name) {
        if (! isset ( $this->{$name} )) {
            $this->{$name} = new Value ( $name, null );
        }
        return $this->{$name};
    }

    public function __set($name, $value) {
        $this->{$name} = new Value ( $name, $value );
    }



}

class Value extends Creator {
    private $name;
    private $value;
    function __construct($name, $value) {
        $this->name = $name;
        $this->value = $value;
    }

    function __toString()
    {
        return (string) $this->value ;
    }
}      
Run Code Online (Sandbox Code Playgroud)

编辑:根据请求提供新阵列支持

class Sample extends Creator {

}

$a = new Sample ();
$a->role = array (
        "A",
        "B",
        "C" 
);


$a->role[0]->nice = "OK" ;

print ($a->role[0]->nice  . PHP_EOL);

$a->role[1]->nice->ok = array("foo","bar","die");

print ($a->role[1]->nice->ok[2]  . PHP_EOL);


$a->role[2]->nice->raw = new stdClass();
$a->role[2]->nice->raw->name = "baba" ;

print ($a->role[2]->nice->raw->name. PHP_EOL);
Run Code Online (Sandbox Code Playgroud)

产量

 Ok die baba
Run Code Online (Sandbox Code Playgroud)

修改后的类

abstract class Creator {
    public function __get($name) {
        if (! isset ( $this->{$name} )) {
            $this->{$name} = new Value ( $name, null );
        }
        return $this->{$name};
    }

    public function __set($name, $value) {
        if (is_array ( $value )) {
            array_walk ( $value, function (&$item, $key) {
                $item = new Value ( $key, $item );
            } );
        }
        $this->{$name} = $value;

    }

}

class Value {
    private $name ;
    function __construct($name, $value) {
        $this->{$name} = $value;
        $this->name = $value ;
    }

    public function __get($name) {
        if (! isset ( $this->{$name} )) {
            $this->{$name} = new Value ( $name, null );
        }

        if ($name == $this->name) {
            return $this->value;
        }

        return $this->{$name};
    }

    public function __set($name, $value) {
        if (is_array ( $value )) {
            array_walk ( $value, function (&$item, $key) {
                $item = new Value ( $key, $item );
            } );
        }
        $this->{$name} = $value;
    }

    public function __toString() {
        return (string) $this->name ;
    }   
}
Run Code Online (Sandbox Code Playgroud)


小智 10

我有同样的错误,没有你的整个代码很难确切地指出如何解决它但它是由没有__set函数引起的.

我过去的方式是我做过这样的事情:

$user = createUser();
$role = $user->role;
$role->rolename = 'Test';
Run Code Online (Sandbox Code Playgroud)

现在如果你这样做:

echo $user->role->rolename;
Run Code Online (Sandbox Code Playgroud)

你应该看'测试'