PHP类将数据写入超出数组顶层的不可访问属性

时间:2015-03-30 23:32:17

标签: php arrays class

我甚至不知道我尝试做什么是可能的,但我想我会检查一下,看看我得到了什么回复。以下是该课程的一个简单示例。

class MyClass {

    public $data = array();

    public function __construct($data) {
        $this->data = $data;
    }

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

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

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

}

我试图开始工作的是以下内容(注意:只有当它很容易且不需要任何其他类或外部源工作时,数据阵列始终保持不变类中的数组):

$obj = new MyClass(array('test' => array()));
$obj->test->add = 'me';

我收到以下消息:

Notice: Indirect modification of overloaded property MyClass::$test has no effect in ...
Warning: Attempt to assign property of non-object in ...

Array
(
    [test] => Array
        (
        )

)

我也尝试过更改__get以通过引用传递:

public function &__get($name) {

这似乎更接近但仍然得到以下消息,这是有道理但不确定如何改变它工作。

Warning: Attempt to assign property of non-object in ...

因此,如果以上所有内容都是愚蠢或根本不是一个好主意,那么以下是一个很好的替代解决方案吗?

$obj = new MyClass(array('test' => array()));
$obj->setTestData('add', 'me');

这可以按预期工作,甚至不使用魔术方法:

Array
(
    [test] => Array
        (
            [add] => me
        )

)

嗯,我希望有人能让我对此感到满意。感谢任何回复!


更新:其他替代方案:

仍然不是我正在寻找的东西,但反正很好..

class MyClass {

    public $data = array();

    public function __construct($data) {
        $this->data = $data;
    }

    public function __get($name) {
        if (!isset($this->data[$name])) {
            $this->data[$name] = new stdClass();
        } else if (is_array($this->data[$name])) {
            $this->data[$name] = @json_decode(@json_encode($this->data[$name], JSON_FORCE_OBJECT), false);
        }
        return $this->data[$name];
    }

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

    public function toArray() {
        return @json_decode(@json_encode($this->data), true);
    }

}

所以当我运行以下内容时:

$o = new MyClass(array('test' => array()));
$o->test->value = 10;
print_r($o->data);

我得到了这个输出:

Array
(
    [test] => stdClass Object
        (
            [value] => 10
        )

)

然后,如果我需要它成为一个数组,我就运行它:

printr($o->toArray());

得到:

Array
(
    [test] => Array
        (
            [value] => 10
        )

)

它也适用于任何深度(我喜欢):

$o = new MyClass(array());
@$o->one->two->three->four->five = 100;
printr($o->toArray());

输出:

Array
(
    [one] => Array
        (
            [two] => Array
                (
                    [three] => Array
                        (
                            [four] => Array
                                (
                                    [five] => 100
                                )

                        )

                )

        )

)

我唯一不喜欢的是我必须使用@:

来抑制警告
@$o->one->two->three->four->five = 100;

如果你没有得到这个:

  

警告:在......

中从空值创建默认对象

我不知道......有什么想法?

1 个答案:

答案 0 :(得分:1)

简答:使用PHP无法实现您的目标。


你可以想象这样的事情:

class MyClass {

    public $data = array();

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

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

$o = new MyClass();
$o->test->val = "foo";
var_dump($o);

这看起来会为不存在(或无法访问!)的属性动态创建stdClass类对象。拥有一个对象,您可以使用->运算符来访问或设置公共属性。

但它不起作用,因为您收到以下消息:

  

PHP注意:间接修改重载属性MyClass :: $ test对

没有影响

它确实无法在PHP中运行..代码需要如下所示:

$o = new MyClass();
$o->test = new stdClass();
$test = $o->test;
$test->val = "foo";
$o->test = $test;
var_dump($o);

注意!对于上面的示例,您不需要__get__set。您只需通过简单地为其分配值就可以将公共属性添加到PHP对象这一事实。


<强>替代:

这个替代方案怎么样:

class MyClass {

    public $data = array();

    public function data($key) {
        if(!isset($this->data[$key])) {
            $this->data[$key] = new stdClass();
        }
        return $this->data[$key];
    }

}

$o = new MyClass();
$o->data('test')->value = 10;