PHP - 超载财产的间接修改PHP - 超载财产的间接修改(PHP - Indirect mo

2019-05-13 20:47发布

我知道这个问题已经被问了好几次,但他们都没有的解决方法,一个真正的答案。 也许有一个我的具体情况。

我建立它使用魔术方法的映射器类__get()来延迟加载其他对象。 它看起来是这样的:

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

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

    return $obj;
}

在我的代码我做的:

$user = createObject('user');
$user->role->rolename;

这工作至今。 该User对象没有一个叫“角色”属性,所以它使用的魔法__get()方法来创建对象,并将其从“角色”对象返回其属性。

但是,当我试图修改“角色名”:

$user = createUser();
$user->role->rolename = 'Test';

然后,它给了我下面的错误:

注意:超载财产的间接改变没有影响

不知道这仍是在PHP一些bug,或者如果它的“预期的行为”,但在任何情况下,它不工作,我想要的方式。 这真是对我来说是表演塞...因为如何在地球上我能够改变延迟加载对象的属性?


编辑:

实际的问题似乎只当我返回一个包含多个对象的数组发生。

我已经添加的示例代码片段其再现的问题:

http://codepad.org/T1iPZm9t

你应该运行这个在你的PHP环境中真正看到了“错误”。 但也有一些是非常有趣的事情在这里。

我试图改变一个对象,这给我的通知“不能改变重载财产”的财产。 但是,如果我以后呼应财产我看到,它实际上没有改变数值...很奇怪...

Answer 1:

很高兴你给我的东西一起玩

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;

产量

test
test
w00

类用于

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 ;
    }
}      

编辑:新的阵列支持的要求

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);

产量

 Ok die baba

修改后的类

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 ;
    }   
}


Answer 2:

所有你需要做的就是添加“&”你__get函数的前面把它作为参考:

public function &__get ( $index )

挣扎与这一个了一段时间。



Answer 3:

我有同样的错误,没有你的整个代码也很难查出究竟如何解决它,但它是由不具有__set功能引起的。

我已经在过去的四周得到的方式是我做了这样的事情:

$user = createUser();
$role = $user->role;
$role->rolename = 'Test';

现在,如果你这样做:

echo $user->role->rolename;

你应该看到“测试”



Answer 4:

虽然我在此讨论很晚了,我认为这可能是有人在将来有用。

我曾面临类似的情况。 对于那些谁不介意和解封重置变量最简单的解决方法是这样做的。 我敢肯定,这是为什么不工作的原因是从其他的答案,并从php.net手动清除。 工作对我来说,最简单的解决方法是

假设:

  1. $object是重载的对象__get__set从基类,这是我的自由修改我不是。
  2. shippingData是我想修改为如现场数组: - PHONE_NUMBER

 

// First store the array in a local variable.
$tempShippingData = $object->shippingData;

unset($object->shippingData);

$tempShippingData['phone_number'] = '888-666-0000' // what ever the value you want to set

$object->shippingData = $tempShippingData; // this will again call the __set and set the array variable

unset($tempShippingData);

注意:此方法是快速的解决方法可以解决这个问题,并得到复制的变量之一。 如果数组太小humungous,它有良好的可强制改写__get方法返回大阵列的参考相当昂贵的复制。



Answer 5:

我收到此通知这样做的:

$var = reset($myClass->my_magic_property);

这个固定:

$tmp = $myClass->my_magic_property;
$var = reset($tmp);


Answer 6:

这是它们不修改或通过引用传递发生由于PHP对待如何重载在于性质。

请参阅手册的有关超载的更多信息。

要解决这个问题,你可以使用一个__set函数或创建createObject方法。

下面是一个__get__set ,提供了一个解决方法,以类似的情况,以你的,你可以简单地修改__set适合您的需求。

注意__get实际上从未返回变量。 和而一旦你在你的对象设置变量不再超载。

/**
 * Get a variable in the event.
 *
 * @param  mixed  $key  Variable name.
 *
 * @return  mixed|null
 */
public function __get($key)
{
    throw new \LogicException(sprintf(
        "Call to undefined event property %s",
        $key
    ));
}

/**
 * Set a variable in the event.
 *
 * @param  string  $key  Name of variable
 *
 * @param  mixed  $value  Value to variable
 *
 * @return  boolean  True
 */
public function __set($key, $value)
{
    if (stripos($key, '_') === 0 && isset($this->$key)) {
        throw new \LogicException(sprintf(
            "%s is a read-only event property", 
            $key
        ));
    }
    $this->$key = $value;
    return true;
}

这将允许:

$object = new obj();
$object->a = array();
$object->a[] = "b";
$object->v = new obj();
$object->v->a = "b";


Answer 7:

我遇到了同样的问题,W00,但我并没有自由改写在这个问题(E_NOTICE)发生组件的基本功能。 我已经能够解决使用问题ArrayObject的在基本型代替阵列() 。 这将返回一个对象,这将defaulty通过引用返回。



文章来源: PHP - Indirect modification of overloaded property