Entries tagged as object_freezer
Speaking at IPC Spring 2009
I will present two sessions at this year's International PHP Conference - Spring Edition:
Cool PHP Objects Sleep on the Couch
Apache CouchDB is a distributed, fault-tolerant and schema-free document-oriented database that provides scalability as a consequence of its design. Due to its RESTful JSON API, talking to CouchDB from PHP is fairly easy, bindings such as PHPillow make this communication even easier.
The PHP Object Freezer provides the low-level functionality to store (“freeze”) and retrieve (“thaw”) any PHP userland object to and from arbitrary object stores. CouchDB is a natural fit for such an object store.
This presentation shows how PHP’s Reflection API can be used to customize the serialization of PHP objects and provides a pragmatic introduction to Apache CouchDB.
PHP Compiler Internals
In this presentation we introduce a new language construct to demonstrate how one might go about modifying the PHP interpreter. The internals of which follow a pattern common to many language implementations, with lexical analysis, parsing, code generation, and execution phases.
By the end of the presentation, it is hoped the audience will see that contributing to the PHP language core is not necessarily as difficult as it might seem.
See you in Berlin in May!
Object-Relational Behavioral Patterns
The Object_Freezer library that I introduced earlier here and here now supports all three object-relational behavioral patterns listed in Martin Fowler's "Patterns of Enterprise Application Architecture" book.
Unit of Work
Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.
This is achieved by automatically hashing objects in
Object_Freezer::freeze(). Upon freezing, only dirty objects are written back to the object storage. An object is dirty if its hash has changed.Identity Map
Ensures that each object gets loaded only once by keeping every loaded object in a map. Looks up objects using the map when referring to them.
This is achieved by caching previously fetched objects in
Object_Freezer_Storage::fetch().Lazy Load
An object that doesn't contain all of the data you need but knows how to get it.
This is achieved by (optionally) replacing aggregated objects in
Object_Freezer_Storage::fetch()with objects ofObject_Freezer_LazyProxy. ALazyProxyobject provides explicit access to the real object through itsgetObject()method and implicit access through its implementations of__call(),__get(), and__set().
The question is: does the name Object-Relational Behavioral Patterns still fit when the objects are not mapped to a relational database but to a schema-free document-oriented database such as Apache CouchDB?
Cool PHP Objects Sleep on the Couch
The Object_Freezer library for PHP provides the low-level functionality to store ("freeze") and fetch ("thaw") any PHP userland object to and from arbitrary object stores.
Today I added an object storage implementation that uses Apache CouchDB as its backend.
Apache CouchDB, the distributed, fault-tolerant and schema-free document-oriented database that provides scalability as a consequence of its design, is a natural fit for such an object store.
The following example shows how the Object_Freezer's new backend for CouchDB can be used to persist PHP objects:
<?php
require 'Object/Freezer/Storage/CouchDB.php';
class Foo
{
public $a;
protected $b;
private $c;
public function __construct($a, $b, $c)
{
$this->a = $a;
$this->b = $b;
$this->c = $c;
}
}
$object = new Foo(1, 2, 3);
var_dump($object);
// Store the object in the database "test" of the
// CouchDB server that is running on localhost:5984.
$storage = new Object_Freezer_Storage_CouchDB('test');
$storage->store($object);
// Freezing the object added the "magic" attributes
// __php_object_freezer_uuid and __php_object_freezer_hash.
var_dump($object);
// Fetch the object (by ID) from the database.
var_dump($storage->fetch($object->__php_object_freezer_uuid));
?>
Below is the output produced by the script above:
object(Foo)#1 (3) { ["a"]=> int(1) ["b":protected]=> int(2) ["c":"Foo":private]=> int(3) } object(Foo)#1 (5) { ["a"]=> int(1) ["b":protected]=> int(2) ["c":"Foo":private]=> int(3) ["__php_object_freezer_uuid"]=> string(36) "8d17b95e-1410-4e54-a70c-064c09c79210" ["__php_object_freezer_hash"]=> string(40) "40cd89ec4ea3b5a1c1419c83b4ea643da5341ab8" } object(Foo)#10 (5) { ["a"]=> int(1) ["b":protected]=> int(2) ["c":"Foo":private]=> int(3) ["__php_object_freezer_uuid"]=> string(36) "8d17b95e-1410-4e54-a70c-064c09c79210" ["__php_object_freezer_hash"]=> string(40) "40cd89ec4ea3b5a1c1419c83b4ea643da5341ab8" }
Here is an overview of the current feature set:
- PHP objects, with the exception of objects of "special" classes such as
ClosureorPDO, can be frozen and thawed. - Graphs of objects, including those that contain circular references, are supported.
- Frozen objects can be stored in and fetched from an Apache CouchDB database.
Freezing and Thawing PHP Objects
One of the many new features that have been added for PHP 5.3 is the setAccessible() method of the ReflectionProperty class that is part of PHP's Reflection API. This method makes protected and private attributes (unfortunately, the class is called ReflectionProperty instead of ReflectionAttribute) of a class or object accessible for the ReflectionProperty::getValue() and ReflectionProperty::setValue() methods, thus making protected and private attributes "open" for full read and write access from the outside.
Among other use cases, this addition to PHP's meta programming capabilities makes the customized serialization of objects possible as illustrated by the following proof-of-concept implementation:
<?php
class Object_Freezer
{
public static function freeze($object)
{
$state = array();
$reflector = new ReflectionObject($object);
foreach ($reflector->getProperties() as $attribute) {
$attribute->setAccessible(TRUE);
$state[$attribute->getName()] =
$attribute->getValue($object);
}
return array(
'className' => get_class($object), 'state' => $state
);
}
public static function thaw(array $frozenObject)
{
if (!class_exists($frozenObject['className'])) {
throw new RuntimeException(
sprintf(
'Class "%s" could not be found.',
$frozenObject['className']
)
);
}
// Use a "trick" to create an object of the class
// without calling its constructor. After all, we
// are not creating a new object but are merely
// thawing a previously created and currently
// frozen one.
$object = unserialize(
sprintf(
'O:%d:"%s":0:{}',
strlen($frozenObject['className']),
$frozenObject['className']
)
);
$reflector = new ReflectionObject($object);
foreach ($frozenObject['state'] as $name => $value) {
$attribute = $reflector->getProperty($name);
$attribute->setAccessible(TRUE);
$attribute->setValue($object, $value);
}
return $object;
}
}
?>
The following snippet of code uses the Object_Freezer class (see above) to "freeze" and "thaw" an object:
<?php
require 'Object/Freezer.php';
class Foo
{
public $a;
protected $b;
private $c;
public function __construct($a, $b, $c)
{
$this->a = $a;
$this->b = $b;
$this->c = $c;
}
}
$object = new Foo(1, 2, 3);
var_dump($object);
$frozenObject = Object_Freezer::freeze($object);
var_dump($frozenObject);
$object = Object_Freezer::thaw($frozenObject);
var_dump($object);
?>
Below is the output produced by the script above:
object(Foo)#1 (3) {
["a"]=>
int(1)
["b":protected]=>
int(2)
["c":"Foo":private]=>
int(3)
}
array(2) {
["className"]=>
string(3) "Foo"
["state"]=>
array(3) {
["a"]=>
int(1)
["b"]=>
int(2)
["c"]=>
int(3)
}
}
object(Foo)#5 (3) {
["a"]=>
int(1)
["b":protected]=>
int(2)
["c":"Foo":private]=>
int(3)
}
The code for the Object_Freezer class (see above) was written by Stefan Priebsch and myself somewhere over the Atlantic ocean during our flight from Frankfurt to Atlanta for the php|works conference earlier this month. However, only as of today (patch) does it actually work.
Update: The code for Object_Freezer is now available on GitHub.