跟踪对象状态

时间:2009-02-11 11:05:22

标签: php oop

在PHP中,跟踪对象状态的最佳方法是什么,判断它是否已被修改?我有一个创建新实体的存储库对象,然后由其他组件读取/修改它们,最终返回到存储库。如果对象已更改,我希望存储库将数据保存回持久存储(DB)。

我可以想到四个选项:

  1. 使用名为$ _modified的内部布尔属性,每个setter在进行修改时都会更新(如果有很多setter,则会很繁琐)。
  2. 使用serialize()和比较字符串的一些可怕的丑陋黑客(我确定这是非常坏主意,但我想我会添加它以保证完整性)
  3. 类似于上面的东西,但有对象属性的哈希值(不确定它是否适用于包含其他对象的对象)
  4. 从对象中取出对象的克隆并比较它们的内容(比听起来更复杂,因为你怎么知道哪个克隆要比较对象?)

    ...或

  5. 其他一些我不知道的聪明伎俩?

  6. 谢谢,
    千斤顶

4 个答案:

答案 0 :(得分:3)

选项1 - 使用布尔标志 - 是最好的方法。在性能,以及一般可用性和可移植性方面。

所有其他选项都会产生过多的开销,在这种情况下根本不需要。

答案 1 :(得分:1)

您可能希望查看Unit of Work模式,因为这是它旨在解决的问题。当对象发生变化时,它们会向UoW注册自己或被动注册,UoW负责跟踪哪些对象已被更改,以及确定在游戏结束时需要将哪些内容保存回数据库。

答案 2 :(得分:1)

首先,我通常认为$ modified或$ dirty属性是最好的解决方案。

但我写作的原因是你的评论是

  如果有很多二传手

,那就太乏味了

我想知道你是不是在使用PHP5?

如果你是,这是__set()魔术方法的完美使用。您甚至可以按原样使用它,从__set()方法调用现有的setter。

例如:

class some_concept
{

    private $x = 1;
    private $y = 2;
    private $dirty = false;

    // This represents your existing setter methods
    function set_y($i)
    {
        $this->y = $i;
    }

    function __set($name, $value)
    {
        if ($value != $this->{$name}) $this->dirty = true;

        return $this->{'set_' . $name}($value);
    }

    function __get($name)
    {
            return $this->{$name};
    }
}

但是,您对比较序列化字符串的想法有一些优点。序列化可能很昂贵。这是真的。

但它是您列表中最准确的解决方案。想象一下,加载上面的对象,将$ y设置为0,然后将其设置回2,然后保存。它脏了吗?它会这样说,但实际上,它处于加载时的状态。

我在这里使用的测试是你的save()有多贵。如果保存是一个非常昂贵的API调用,数据库事务等,那么您可能会发现在加载时序列化对象并保存它的md5哈希是值得的。

如果那个需要几分之一秒的操作可以节省多秒的交易,那么它真的值得。


最后,我想指出Damien Katz对这一主题的反对意见。 Katz是一位才华横溢的开发人员,他创建了CouchDb,目前在MySQL工作。

他的Error Codes v Exceptions帖子篇幅很长,但对此话题的阅读非常好。

虽然它开始讨论返回抛出异常的错误代码的优点,但他最终还是谈到了如何编写可靠的软件。

首先,他讨论了如何以与SQL事务相同的方式创建原子类。一般的想法是你制作一个对象的副本,修改它的状态,并且只有在最后一步,如果成功,你是否将该副本交换为主要对象。这允许有意义的撤消功能。像这样的模式虽然难以融入现有的应用程序,但也提供了这个is_modified问题的解决方案。

答案 3 :(得分:0)

我认为第一个选项最适合更易读的代码和更快的执行。我还会考虑首先序列化对象(比如文件),然后对内容进行散列。

相同的内容应该产生相同的哈希值。