Cool Objects Sleep on the Couch

Sebastian Bergmann » 27 May 2009 » in Presentations » 1 Comment

Defined tags for this entry: , , ,

Speaking at IPC Spring 2009

Sebastian Bergmann » 27 February 2009 » in Events, Presentations » 2 Comments

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!

Defined tags for this entry: , , ,

Object-Relational Behavioral Patterns

Sebastian Bergmann » 16 February 2009 » in New Features » 2 Comments

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 of Object_Freezer_LazyProxy. A LazyProxy object provides explicit access to the real object through its getObject() 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?

Defined tags for this entry: ,

Cool PHP Objects Sleep on the Couch

Sebastian Bergmann » 11 January 2009 » in New Features » 0 Comments

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 Closure or PDO, 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.
Defined tags for this entry: , ,

Freezing and Thawing PHP Objects

Sebastian Bergmann » 29 November 2008 » in Articles, New Features » 12 Comments

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.

Defined tags for this entry: , ,