views:

187

answers:

2

I'm trying to track all changes made to a PHP variable. The variable can be an object or array.

For example it looks something like:

$object = array('a', 'b');

This object is then persisted to storage using an object-cache. When php script runs again.

So when the script runs the second time, or another script runs and modifies that object, I want those modifications to be tracked, either as they are being done, or in one go after the script executes.

eg:

$object[] = 'c';

I would like to know that 'c' was added to the object.

Now the actually code looks something like this:

$storage = new Storage();
$storage->object = array('a', 'b');

second load:

$storage = new Storage();

var_dump($storage->object); // array('a', 'b')

$storage->object[] = 'c';

What I want to know is that 'c' was pushed into $storage->object so in the class "Storage" I can set that value to persistent storage.

I have tried a few methods, that work, but have downsides.

1) Wrap all objects in a class "Storable" which tracks changes to the object

The class "Storable" just saves the actual data object as a property, and then provides __get() and __set() methods to access it. When a member/property of the object is modified or added, the "Storable" class notes this. When a a property is accessed __get() on the Storable class returns the property, wrapped in another Storable class so that changes on that are tracked also, recursively for each new level.

The problem is that the objects are no longer native data types, and thus you cannot run array functions on arrays.

eg:

$storage = new Storage();

var_dump($storage->object); // array('a', 'b')

array_push($storage->object, 'c'); // fails

So instead we'd have to implement these array functions as methods of Storable.

eg:

$storage = new Storage();

var_dump($storage->object); // array('a', 'b')

$storage->object->push('c');

This is all good, but I'd like to know if its possible to somehow use native functions, to reduce the overhead on the library I'm developing, while tracking changes so any changes can be added to persistent storage.

2) Forget about tracking changes, and just update whole object structures

This is the simplest method of keeping the objects in the program synchronized with the objects actually stored in the object-cache (which can be on a different machine).

However, it means whole structures, like an array with 1000 indexes, have to be sent though a socket to the object-cache when a single index changes.

3) Keep a mirror of the object locally

I've also tried cloning the object, and keeping a clone object untouched. Then when all processing is done by the PHP script, compare the clone to the modified object recursively, and submitting changed properties back to the object-cache.

This however requires that the whole object be downloaded in order to use it. It also requires that the object take up twice as much memory, since it is cloned.


I know this is pretty vague, but there is a quite a bit of code involved. If anyone wants to see the code I can post it, or put it up on an open SVN repo. The project is open source but I haven't set up a public repository yet.

+1  A: 

In all honesty I would reconsider what you're doing. You're really trying to turn PHP into something it's not. This is the kind of ORM you see in Java and C# not PHP, which is basically transient in nature (meaning everything, barring memcache/APC/etc, is recreated on each request). This is anathema to sophisticated object caching and change tracking.

That being said, the only way you could do this is wrap everything in something that overloads __get(), __set() and __isset() and implements ArrayAccess.

cletus
This actually is an interface to object caches, including memcache and APC. I believe PHP's transient nature is a benefit here.
bucabay
Would implementating ArrayAccess allow all Array functions eg: array_pop() to be used on it?
bucabay
+1 for __get and __set
Josh
+1  A: 

Since your 'object' is really an array, you can't add functionality to it. Your idea of encapsulating it with class methods is the correct approach. Worrying about performance over proper design at this stage is irrelevant and misguided - the overhead you incur with this approach will likely be insignificant to your overall application performance.

You should look into the SPL array classes such as ArrayObject. They provide a complete array-like interface and are easily extendable.

Eran Galperin
Thanks. When I said overhead I meant amount of code writing and not performance. I guess that is misguided also, I'm just a lazy programmer trying to do the least work I have to. I guess the Array interfaces would be the way to go.
bucabay