使用具有多维数组的Setter

时间:2011-05-03 22:13:57

标签: php mongodb object getter-setter

我正在尝试为PHP中的对象创建__set,该对象适用于多维数组。这甚至可能吗?

我希望能够得到以下内容:$post->comments[0]['uid']=3;。但是,注释实际上将成为私有缓存变量$_cache['comments']=array()中的关键。如果__set函数可以某种方式同时获得基本键(注释)和索引(0)以及它设置的键/值(uid / 3),那将是很好的。但是,这是不可能的。

我考虑过制作$_cache['comments']和ArrayObjects数组,但这不允许我定义自定义_ get / _set重载。相反,我认为我可能最终必须创建一个新的Comments对象,然后用这些填充数组。但是,我真的不想这样做,如果PHP能够在__set重载中处理嵌套数组,那就太好了。

我正在使用Mongo,并希望我能为每个文档只有一个对象。但是,Mongo中的数组对象给我带来了一些问题。我想在PHP中将它们作为一个数组处理,但这似乎不可能。 setter需要$post->comments[0]['uid']=3并更新缓存以及设置$this->data['comments'][0]['uid']=3

我知道如果评论是一个对象数组,我可以这样做:

$post->comments[0]->uid=3; 
///Sets $_cache['comments'][0]->uid=3;

它会起作用,因为注释的getter将返回对象数组并允许它访问uid属性。然后我可以在comments对象中有一个getter / setter,它会通过伪“friend”函数/ hack以某种方式编辑$post->data。但是,我没有看到使用数组实现这一目标的简单方法....

有什么建议吗?

5 个答案:

答案 0 :(得分:1)

这比你想象的要复杂得多。你可以通过一堆变通方法来完成你想要的东西,但它很少值得付出努力。

如果使用getter方法解析->comments本身,那么为[0]子数组分配内容实际上不会在私有属性中结束。 ->comments[0]=甚至不会调用你的setter方法。相反,这是一个读访问。

要完成这项工作,您必须使__get方法返回& $this->_cache['comments']的引用。

如果要拦截comments数组中的集访问,则确实需要ArrayObject。不同之处在于,这需要覆盖offsetGetoffsetSet,而不是__get__set。但同样,由于您正在访问另一个子数组,实际上将使用__get方法,您需要返回另一个引用,或者再次返回一个ArrayObject解决方法goo。

答案 1 :(得分:1)

在构建我自己的PHP包装类时,我跳过了其中一些箍。

https://github.com/gatesvp/MongoModel

它仍处于工作中,但它确实处理了一些基本的“将此对象映射到数据库”。

答案 2 :(得分:1)

在PHP聊天室或者对你有用的php文档中几乎没有什么值得写的,Adam。大多数建议都倾向于在S​​PL中实施interface ArrayAccess或扩展class ArrayObject。实际上,对于您的问题,有一个令人惊讶的直接解决方案:$post->comments[0]['uid']=3使用重载的setter __set()

在班级private $comments = array();中定义post。为方便起见,使用$comments的第一个下标的文本键:这里,整数0变为“零”。然后按如下方式调用setter:

$post->zero = ['uid', 3];

这会调用魔术设置器,因为类$zero中没有公开声明的属性post:“在与尚未声明或未显示的属性或方法交互时调用重载方法目前的范围。“ (Overloading上的PHP 5手册页。)

setter也可以是setComments(),这是一种方便,因为您不必区分传入属性以识别那些用于数组comments的属性,但调用语法变得不那么自然了。

你的重载,自动魔法函数__set会收到两个参数:属性和值:

public function __set($property, $value) {

非常让人联想到Crockford的JSON协议。用这些术语来思考它是有帮助的。

由于您发送的属性“零”在类post中不存在,因此它需要被捕获,而我的首选方法,因为属性comments中的第一个下标可能会有多个值,是在post中定义一个受支持的下标值的私有数组:

private $indices = [
     "zero"  => 0,
     "one"   => 1,
     "two"   => 2,
     "three" => 3 
];

comments的索引作为__set()到达$property时,会验证其存在于$indices中。现在,您只需遍历$value中提供的数组,即可 uid及其相应的值,然后按如下方式分配给$comments

public function __set($property, $value) {
    if (array_key_exists($property, $this->indices) && is_array($value))
        foreach ($value as $uid => $uid_value)  
            $this->comments[$this->indices[property]][$uid] = $uid_value;
    else
        ...
}

使用$this->indices[property]来提取要使用的整数值0 索引comments的第一个维度,并使用值int 3提取$uid_value以进行分配。

这里概述的方法不是噱头,解决方法或聪明的伎俩。这是一种简单的设计技术,旨在与SPL的一个设施一起使用,原则上可以扩展到任意维度的阵列。我在生产系统中实现了设计,所以如果你仍然遇到困难,请在这里发帖,我会帮你调试你的应用程序。祝你好运!

答案 3 :(得分:0)

我相信你可以做的最重要的是重载一些属性是使用这里定义的魔术方法__set():http://us.php.net/ __ set

我不确定在PHP编译器获取之前你能否处理[0] ......

所以你的另一个解决方案是将注释转换为方法

public function comments($id) {
   return $this->obj[$id]; // Obj
}

您返回的对象具有__set属性

class Obj {
   private $id;
   public function __set($key, $value) {
       if($key === 'uid') {
           $_cache = $GLOBALS['_cache'];
           $_cache['comments'][$this->id]->uid = $value;
       }
   }
}

这里缺少很多代码,但你可以通过这个__set方法找出如何做到这一点()

答案 4 :(得分:0)

创建一个函数,而不是试图在一些甚至没有意义的东西之上进行破解。

public function setCommentUid($commentId, $uid) {
    $this->_cache['comments'][$commentId]->uid = $uid;
}

//then...
$post->setCommentUid(0, 3);

这使得使用该类变得更加简单,并且更容易看到它的作用。