tags:

views:

102

answers:

4

Hi,
In PHP, what's the best way to track an objects state, to tell whether or not it has been modified? I have a repository object that creates new entities, they are then read/modified by other components and eventually given back to the repository. If the object has changed I want the repository to save the data back to the persistent storage (DB).

I can think of four options:

  1. Use an internal boolean property called $_modified, which every setter updates when modifications are made (tedious if there are a lot of setters).
  2. Some horrible ugly hack using serialize() and comparing the strings (I'm sure this is a very bad idea, but I thought I'd add it for completeness)
  3. Something like the above but with a hash of the objects properties (not sure if it would work with objects that contain other objects)
  4. Taking clones of the objects as they come out of the repo and comparing what comes in (more complicated than it sounds, because how do you know which clone to compare the object to?)

    or...

  5. Some other clever trick I'm not aware of?

Thanks,
Jack

+3  A: 

Option 1 - using a boolean flag - is the best way. In terms of performance, as well as general usability and portability.

All the other options incur excessive overhead which is simply not needed in this case.

Yuval A
Yeah, you're absolutely right, thanks.
Jack Sleight
fyi: the flag is often called "dirty flag". If an object is "dirty", it has changed since 'last time'.
Henrik Paul
Couldn't agree more.
Syntax
A: 

I think the first option is the best for more readable code and faster execution. I would also consider serializing the objects first(say to file) and then hashing the contents.

The same contents should produce the same hash value.

Lonzo
+1  A: 

You might want to look into the Unit of Work pattern, as this is much the problem which it is designed to tackle. As objects are changed, they register themselves, or are passively registered, with the UoW, which is responsible for keeping track of which objects have been changed, and for figuring out what needs to be saved back to the database at the end of play.

12345
+1  A: 

First, I generally think a $modified or $dirty property is the best solution here.

But the reason I'm writing was your comment that it would be

tedious if there are a lot of setters

I'm wondering if you're not using PHP5?

If you are, this is a perfect use of the __set() magic method. You could even use it as-is, calling your existing setters from the __set() method.

For example:

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

However, there is some merit to your idea of comparing serialized strings. Serialization can be expensive. It's true.

But it is the most accurate solution on your list. Imagine loading the object above, setting $y to 0, then setting it back to 2, then saving. Is it dirty? It will say so, but in reality, it's in the same state it was when it was loaded.

The test I would use here is how expensive is your save(). If saving is a very expensive API call, DB transaction, etc, then you might find that it's worth the expense to serialize the object on-load and save an md5 hash of it.

If that op, which will take a fraction of a second, can save a multi-second transaction, then it could really be worth it.


Finally, I want to point out a contrarian opinion on this subject from Damien Katz. Katz is a talented developer who created CouchDb, and currently works for MySQL.

His Error Codes v Exceptions post is long but a very good read on this topic.

While it begins talking about the merits of returning an Error Code of throwing an Exception, he really ends up talking about how to write solid software.

Primarily, he talks about how to create classes that are atomic in the same way that SQL Transactions are. The general idea being that you make a copy of an object, modify it its state, and, only on the last step, if successful, do you swap that copy out for the primary object. That allows meaningful undo features. A pattern like this, while difficult to shim into an existing app, also provides a solution to this is_modified problem.

Encoderer