Blog Archive

Sunday, 13 October 2013

Active Record vs Data Mapper for Persistence

These two design patterns are explained in Martin Fowler's book 'Patterns of Enterprise Application Architecture', and represent ways of handling data persistence in object oriented programming. Here are the basics:

Active Record Example

class Foo 
{
    protected $db;
    public $id;
    public $bar;
    
    public function __construct(PDO $db)
    {
        $this->db = $db;
    }

    public function do_something()
    {
        $this->bar .= uniqid();
    }

    public function save()
    {
        if ($this->id) {
            $sql = "UPDATE foo SET bar = :bar WHERE id = :id";
            $statement = $this->db->prepare($sql);
            $statement->bindParam("bar", $this->bar);
            $statement->bindParam("id", $this->id);
            $statement->execute();
        }
        else {
            $sql = "INSERT INTO foo (bar) VALUES (:bar)";
            $statement = $this->db->prepare($sql);
            $statement->bindParam("bar", $this->bar);
            $statement->execute();
            $this->id = $this->db->lastInsertId();
        }
    }
}

//Insert
$foo = new Foo($db);
$foo->bar = 'baz';
$foo->save();


In this simplified example, a database handle is injected into the constructor of Foo (using dependency injection here allows the object to be unit tested without using a real database), and Foo uses that to save its own data. The do_something method is just a placeholder for some business logic.

Active Record advantages

  • It is fairly quick and easy to write an active record object, particularly when the properties of the object correlate directly with columns in the database.
  • Everything is kept in one place, making it easier to see how the code works.

Active Record disadvantages

  • The Active Record pattern breakes SOLID design principles - in particular the Single Responsibility Principle (SRP - the 'S' of SOLID). According to the SRP, a domain object should only have a single responsibility, ie. its own business logic. By asking it to handle persistence as well, you are giving it an additional responsibility, and this increases the complexity of the object - making it more difficult to maintain and test.
  • The persistence implementation is closely coupled with the business logic, meaning that if you later wanted to use a different persistence layer (for example to store the data in an XML file instead of a database), you would need to refactor the code.

Data Mapper Example

class Foo 
{
    public $id;
    public $bar;

    public function do_something()
    {
        $this->bar .= uniqid();
    }
}

class FooMapper
{
    protected $db;

    public function __construct(PDO $db)
    {
        $this->db = $db;
    }
    public function saveFoo(Foo &$foo)
    {
        if ($foo->id) {
            $sql = "UPDATE foo SET bar = :bar WHERE id = :id";
            $statement = $this->db->prepare($sql);
            $statement->bindParam("bar", $foo->bar);
            $statement->bindParam("id", $foo->id);
            $statement->execute();
        }
        else {
            $sql = "INSERT INTO foo (bar) VALUES (:bar)";
            $statement = $this->db->prepare($sql);
            $statement->bindParam("bar", $foo->bar);
            $statement->execute();
            $foo->id = $this->db->lastInsertId();
        }
    }
}

//Insert
$foo = new Foo();
$foo->bar = 'baz';
$mapper = new FooMapper($db);
$mapper->saveFoo($foo);


Here the Foo class is a lot simpler and only has to worry about its own business logic. Not only does it not have to persist its own data, it doesn't even know or care whether its data is persisted at all. The FooMapper class doesn't contain any business logic, but it does handle the data persistence, and all of the SQL is tucked away in the mapper class.

Data Mapper advantages

  • Each object has a single responsibility, thus preserving the integrity of SOLID design principles, and keeping each object simple and to the point.
  • The business logic and persistence are loosely coupled - if you want to persist in an XML file or some other format, you can just write a new mapper and don't have to touch the domain object.

Data Mapper disadvantages

  • You have to think a bit harder before you type!
  • You end up with more objects to manage, which makes the calling code a little more complex and slightly harder to follow.

Service Objects

When using the data mapper pattern, the calling code has to choose a mapper object and a business object and put them together. If this calling code is in your controller, you could end up having your model layer leak into your controller, and this can cause more difficulties with maintenance and unit testing. This problem can be resolved by introducing a service object. The service object is the gateway between the controller and the model, and it handles marrying up domain objects with their mappers as necessary.

It should of course be remembered that the M in MVC, represents a model layer, not necessarily a model object. There could be several types of object in a single model (in the above example, you could have a service object, domain object, and data mapper object, all forming a single model). If you use the active record pattern on the other hand, your model could well be just a single object.

Which option to use

Active record objects have historically been very popular due to them being simpler, easier to understand and quicker to write, and many PHP frameworks and ORMs use the active record pattern by default. If you are confident that you will never need to swap out the persistence layer (perhaps when dealing with an object which represents an .ini file for example), or are dealing with very simple objects that don't have much (or even any) business logic, or just prefer to keep things contained in fewer classes, the active record pattern may make the most sense.

Using a data mapper though does lead to cleaner, easier to test, easier to maintain code, and allows for greater extensibility - at the cost of slightly increased complexity. If you haven't tried it before, give it a whirl - you might like it.

Monday, 23 September 2013

Public properties, getters and setters, or magic?

Opinion seems to be divided on whether it is good practice to use public properties in PHP classes, or whether to use getter and setter methods instead (and keep the properties private or protected). A sort of hybrid third option is to use the magic methods __get() and __set(). As always, there are advantages and disadvantages to each approach, so let's take a look at them...

Public properties example

class Foo 
{
    public $bar;
}

$foo = new Foo();
$foo->bar = 1;
$foo->bar++;

In this example, bar is a public property of Foo. The calling code can manipulate that property in any way it likes, and stuff any old data in it.

Public properties advantages

  • Compared with getter and setter methods, there is a lot less typing involved!
  • The calling code is more readable and easier to work with than getter and setter method calls.
  • A call to a public property (to either set or get) is faster and uses less memory than a method call - but the saving is small unless you are calling it many times in a long loop.
  • Objects with public properties can be used as parameters for some PHP functions (such as http_build_query), and can be serialized by json_encode.

Public properties disadvantages

  • There is no way of controlling what data is held in the properties - it is very easy to populate them with data that the class methods might not expect. This can be particularly problematic if the class is being used by another developer (ie. other than the author of the class), as they might not (and should not need to) be aware of the internal workings of the class (and let's face it, after a few months, the author of the class probably won't remember the internal workings either).
  • If you want to expose a public property in an API, you can't do so using an interface, as in PHP interfaces only allow method definitions.

Using getters and setters example

class Foo
{
    private $bar;
    
    public function getBar()
    {
        return $this->bar;
    }
    
    public function setBar($bar)
    {
        $this->bar = $bar;
    }
}

$foo = new Foo();
$foo->setBar(1);
$foo->setBar($foo->getBar() + 1);

Here the bar property is private so cannot be accessed by the calling code directly. The caller has to use the getBar method to retrieve the value and the setBar method to set it. The methods can perform validation processing to ensure that only valid values are allowed through.

Getters and setters advantages

  • With getters and setters you can control exactly what is stored in your object properties, and reject any values that are not valid.
  • You also have the option of performing additional processing when a value is set or retrieved (for example, if updating this property should trigger some action such as notifying an observer).
  • When setting a value which represents an object or array (rather than a scalar value), you can specify the type in the function declaration (eg. public function setBar(Bar $bar)). Such a damn shame PHP won't let you do the same thing with ints and strings!
  • If the value of a property has to be loaded from an external data source or the runtime environment, you can lazy load it - so the resources required to load the data are only used if the property itself is called. Of course you would need to be careful that you don't needlessly load the data from the external source on every call to the property. And it would be more common to make a single call to the database to populate all the properties rather than fetching them one at a time.
  • You can make properties read-only or write-only by only creating a getter but not a setter or vice-versa.
  • You can include a getter and setter in an interface to expose them in an API.

Getters and setters disadvantages

  • For developers who are used to accessing properties directly, getters and setters are a pain in the neck to use! For every property you have to define the property itself, a getter, and a setter, and to use the property in the calling code you have to make extra method calls - it is much easier to say $foo->bar++; rather than the long-winded $foo->setBar($foo->getBar() + 1); (although of course you could add yet another method such as $foo->incrementBar();)
  • As noted above, there is a small additional overhead when making a method call over using a plain ol' public property.
  • By convention, getter and setter methods start with the verbs 'get' and 'set' respectively, but these verbs are also commonly used for other methods which don't necessarily relate to properties. This is not necessarily a problem for the calling code as you might not care what the implementation is, but the ambiguity about the type of implementation you are dealing with can make the code harder to understand.

Magic method getters and setters example

class Foo
{
    protected $bar;

    public function __get($property)
    {
        switch ($property)
        {
            case 'bar':
                return $this->bar;
            //etc.
        }
    }

    public function __set($property, $value)
    {
        switch ($property)
        {
            case 'bar':
                $this->bar = $value;
                break;
            //etc.
        }
    }
}

$foo = new Foo();
$foo->bar = 1;
$foo->bar++;

Here, the bar property is not publicly exposed, but the calling code still calls it as though it were public. When PHP can't find a matching public property, it calls the appropriate magic method (__get() for retrieving a value, __set() for assigning a value). This might seem like the best of both worlds, but it has a major drawback (see disadvantages below!). Note also that __get and __set are NOT called if a matching public property exists, but they are called if a protected or private property exists but is out of scope, or if no property exists.

Magic method getter and setter advantages

  • You can manipulate properties directly from the calling code (as though they were public properties) but still have complete control over what data goes into what property.
  • As with declared getter and setter methods, you can perform additional processing when the property is used.
  • You can use lazy loading.
  • You can make properties read-only or write-only.
  • You can use the magic methods as a catch-all to handle calls to properties that don't exist, and still process them in some way (effectively allowing the calling code to decide what property names to use).

Magic method getter and setter disadvantages

  • The showstopper for magic methods is that they do not expose the property in any way. To use or extend the class, you have to 'just know' what properties it supports. This is simply unacceptable most of the time (unless perhaps you are one of those hard core programmers who think notepad is an IDE!), although there are times when the advantages mentioned above outweigh this limitation. As pointed out by a commentator below, this disadvantage can be overcome by using the phpDoc tags @property, @property-read, and @property-write. Cool.

Which option to use

Clearly there are some significant advantages to getters and setters, and some people feel that they should therefore be used all the time (especially those who come from a Java background!). But in my opinion, they do break the natural flow of the language, and their additional complexity and verbosity puts me off using them unless there is a need to do so (I find it a little irritating when naive getters and setters don't actually DO anything other than get or set the property). My choice then is to use public properties most of the time, but getters and setters for critical settings that I feel need stricter control, would benefit from lazy loading, or that I want to expose in an interface.

Another alternative?

Before I learned PHP, I used to use C#. In C#, all properties have accessor methods, but you don't have to call them as methods, you can just manipulate the properties directly and the corresponding methods are called magically. So it is similar to PHP's magic __get and __set, but the properties are still declared and exposed. This really is the best of both worlds, and it would be great to see a feature like this in PHP.

Tragically though, the RFC for a C#-like property accessor syntax feature could not quite muster up the two-thirds majority needed to take it forward: https://wiki.php.net/rfc/propertygetsetsyntax-v1.2 Bah!