An Intro to Virtual Proxies, Part 1

This entry is part 1 of 2 in the series An Intro to Virtual Proxies

An Intro to Virtual Proxies

One of the most appealing facets of Polymorphism is that it is applicable in a wide variety of situations. Moreover, while the ability to switch out concrete implementations is in and of itself a fundamental object-oriented pillar, commonly used for creating loosely-coupled, interchangeable components, its usage falls shy when it comes to pulling on the reins of domain objects.

There’s a somewhat fragile rationale that stands behind this observation: in many cases, domain objects are conceptually modelled up front to operate on concrete sets of data and inside the boundaries of strict relationships which most likely won’t change over time, and where most of the varying business logic is placed in hierarchies of standalone strategy classes (here’s where actual Polymorphism takes place). In such cases, certainly there’s not much room or even compelling reasons to justify having different implementations of domain objects at runtime except for mocking/testing.

Furthermore, very few will disagree that programming to interfaces is a bad thing, but isn’t it overkill to have one per domain object? After all, a user object will always be modelled with a few typical roles in mind, and if its login() method ever needs to be updated, well… it’ll just be refactored accordingly and the client code won’t complain so long as the mutual contract is maintained. At a glance, it seems that having a whole new user implementation not only isn’t very pragmatic, but it’s simply absurd.

A common pitfall with this approach is made apparent when it’s necessary to pull in an aggregate (a domain object made up of other objects or collections) from the database. As each reference to the aggregate implies dealing face to face with the real domain objects, the process unavoidably ends up dropping the entire object graph into the client. It’s not exactly a solution to praise with fervency, even if the objects can be cached later on.

As usual, simple solutions are the most effective ones, and this applies to the above problem. Rather than fetching the real fat aggregate, if a lightweight substitute is used instead which shares the same interface and knows how to get the aggregate in question from storage then lazy-loading the underlying objects becomes a straightforward process. Often referenced by a few other fancy names, the substitute is generically called a virtual proxy, a sort of stand-in that exploits the neatness of Polymorphism and interacts with the actual domain objects.

Proxies aren’t new to PHP. Doctrine and Zend Framework 2.x make use of them, although with different aims. On behalf of a didactic cause, however, it would be pretty instructive to implement some custom proxy classes and use them for lazy-loading a few basic aggregates from the database, this way illustrating how virtual proxies do their stuff under the hood.

Considering the functionality of proxies can be easily accommodated to coordinate either with single domain objects or with collections of them (or both), in the first part of this two-part series I’ll be showcasing the former user case, while in the second installment I’ll dig deeper into the complexities of the latter.

So, let’s now move along and get things finally rolling with virtual proxies.

Setting Up a Domain Model

As I pointed out in the introduction, proxies are simple -yet powerful- structures that allow you to pull in requested domain objects from underlying storage. But as one might expect, it would first be warranted to create a simple Domain Model so at least one of its building objects can be interfaced to a proxy.

The fist domain class I’ll add to the sample model will be one that represents blog posts. The class, along with its segregated interface, look like this:

<?php
namespace Model;

interface PostInterface
{
    public function setId($id);
    public function getId();

    public function setTitle($title);
    public function getTitle();

    public function setContent($content);
    public function getContent();

    public function setAuthor(AuthorInterface $author);
    public function getAuthor();
}
<?php
namespace Model;

class Post implements PostInterface
{
    protected $id;
    protected $title;
    protected $content;
    protected $author;

    public function __construct($title, $content, AuthorInterface $author) {
        $this->setTitle($title);
        $this->setContent($content);
        $this->setAuthor($author);
    }

    public function setId($id) {
        if ($this->id !== null) {
            throw new BadMethodCallException(
                "The ID for this post has been set already.");
        }

        if (!is_int($id) || $id < 1) {
            throw new InvalidArgumentException(
                "The post ID is invalid.");
        }

        $this->id = $id;
        return $this;
    }

    public function getId() {
        return $this->id;
    }

    public function setTitle($title) {
        if (!is_string($title) 
            || strlen($title) < 2 
            || strlen($title) > 100) {
            throw new InvalidArgumentException(
                "The post title is invalid.");
        }

        $this->title = htmlspecialchars(trim($title), ENT_QUOTES);
        return $this;
    }

    public function getTitle() {
        return $this->title;
    }

    public function setContent($content) {
        if (!is_string($content) || strlen($content) < 2) {
            throw new InvalidArgumentException(
                "The post content is invalid.");
        }

        $this->content = htmlspecialchars(trim($content), ENT_QUOTES);
        return $this;
    }

    public function getContent() {
        return $this->content;
    }

    public function setAuthor(AuthorInterface $author) {
        $this->author = $author;
        return $this;
    }

    public function getAuthor() {
        return $this->author;
    }
}

The behavior of the Post class is trivial as it just implements a few mutators/accessors with some basic filtering/validation. Notice, however, that the class injects an author’s implementation in the constructor, that way setting a one-to-one relationship with the corresponding author.

To get the domain model up and running, the author in question must be modeled as well. Here’s the related class, along with its contract:

<?php
namespace Model;

interface AuthorInterface
{
    public function setId($id);
    public function getId();

    public function setName($name);
    public function getName();

    public function setEmail($email);
    public function getEmail();
}
<?php
namespace Model;

class Author implements AuthorInterface
{
    protected $id;
    protected $name;
    protected $email;

    public function __construct($name, $email) {
        $this->setName($name);
        $this->setEmail($email);
    }

    public function setId($id) {
        if ($this->id !== null) {
            throw new BadMethodCallException(
                "The ID for this author has been set already.");
        }

        if (!is_int($id) || $id < 1) {
            throw new InvalidArgumentException(
                "The author ID is invalid.");
        }

        $this->id = $id;
        return $this;
    }

    public function getId() {
        return $this->id;
    }

    public function setName($name) {
        if (strlen($name) < 2 || strlen($name) > 30) {
            throw new InvalidArgumentException(
                "The name of the author is invalid.");
        }

        $this->name = htmlspecialchars(trim($name), ENT_QUOTES);
        return $this;
    }

    public function getName() {
        return $this->name;
    }

    public function setEmail($email) {
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            throw new InvalidArgumentException(
                "The email of the author is invalid.");
        }

        $this->email = $email;
        return $this;
    }

    public function getEmail() {
        return $this->email;
    }
}

The same that I just said about the Post class applies to its collaborator, Author. There subtle detail worth stressing here is this: if the domain model were put to roll down the road right now, then any post object pulled in from the database would get an author object eagerly attached to it, something that fully honors its condition of aggregate.

While this is all well and fine since authors aren’t expensive to set per se, there might be times when they could be loaded only on request. If this happens, all the last-minute retrieval logic should be placed outside the domain objects’ confines, but at the same time controlled by an object that understands the model.

There’s no need to sink in the waters of anguish here, as this apparently-complex condition has a dead simple solution: if an author proxy is used instead of a real author, then it’s feasible to lazy-load the latter without spoiling the contract with client code since the proxy exposes the same API. This itself proves Polymorphism is hard to knock when it comes to swapping out domain object implementations in order to optimize your database persistence/retrieval strategy.

Curiosity is a pretty itching bug indeed, so let’s satisfy our own one and see how to create the above mentioned author proxy.

Loading Authors on Request via Virtual Proxies

Considering the proxy should be able to fetch author objects from the database, a neat way to do so would be through the API of a data mapper. In this particular case, the one shown below will get the job done nicely:

<?php namespace ModelMapper;

interface AuthorMapperInterface
{
    public function fetchById($id);
}
<?php
namespace ModelMapper;
use LibraryDatabaseDatabaseAdapterInterface,
    ModelAuthor;

class AuthorMapper implements AuthorMapperInterface
{    
    protected $entityTable = "authors";
    
    public function __construct(DatabaseAdapterInterface $adapter) {
        $this->adapter = $adapter;
    }
    
    public function fetchById($id) {
        $this->adapter->select($this->entityTable, 
            array("id" => $id));
        
        if (!$row = $this->adapter->fetch()) {
            return null;
        }
        
        return new Author($row["name"], $row["email"]);
    }
}

So far, so good. With the user mapper already in place, it’s time to tackle the creation of the author proxy. As stated before, it shares the same interface with the one implemented by real authors, and its core implementation is as follows:

<?php
namespace ModelProxy;
use ModelMapperAuthorMapperInterface,
    ModelAuthorInterface;

class AuthorProxy implements AuthorInterface
{
    protected $author;
    protected $authorId;
    protected $authorMapper;

    public function __construct($authorId, AuthorMapperInterface $authorMapper) {
        $this->authorId = $authorId;
        $this->authorMapper = $authorMapper;
    }
    
    public function setId($id) {
        $this->authorId = $id;
        return $this;
    }
    
    public function getId() {
        return $this->authorId;
    }

    public function setName($name) {
        $this->loadAuthor();
        $this->author->setName($name);
        return $this;
    }
    
    public function getName() {
        $this->loadAuthor();
        return $this->author->getName();
    }
    
    public function setEmail($email) {
        $this->loadAuthor();
        $this->author->setEmail($email);
        return $this;
    }
    
    public function getEmail() {
        $this->loadAuthor();
        return $this->author->getEmail();
    }
    
    protected function loadAuthor() {
        if ($this->author === null) {
            
            if(!$this->author = $this->authorMapper->fetchById($this->authorId)) {
                throw new UnexpectedValueException(
                    "Unable to fetch the author.");
            }
        }
        
        return $this->author;
    }
}

At a quick glance the AuthorProxy class looks like a cheap and dirty duplicate of Author with little or no extra functionality, but I assure you this is nothing but a shallow impression. When analyzed it shows the logic that stands behind a virtual proxy in a nutshell. The loadAuthor() method is the proxy’s actual workhorse, as its responsibility is to fetch from the database once, and only once, an author object is injected into the constructor. The batch of additional methods are just wrappers for the author’ setters/getters.

All in all it should be clear that constructing a proxy class that transparently handles a few domain objects behind the scenes is a lot more approachable than one might think. Even so, the best way for catching up the proxy’s real strength is by example. Let’s suppose we need to build an application that fetches a few popular quotes from a database and then dumps them to screen along with their corresponding author.

In a simple implementation, the application would look pretty much like this:

<?php
use LibraryLoaderAutoloader,
    LibraryDatabasePdoAdapter,
    ModelMapperAuthorMapper,
    ModelProxyAuthorProxy,
    ModelAuthor,  
    ModelPost;
    
require_once __DIR__ . "/Library/Loader/Autoloader.php";
$autoloader = new Autoloader;
$autoloader->register();

$adapter = new PdoAdapter("mysql:dbname=mydatabase", "dbuser", "dbpassword");

$authorMapper = new AuthorMapper($adapter);

$author = $authorMapper->fetchById(1);

$post = new Post(
    "About Men",
    "Men are born ignorant, not stupid; they are made stupid by education.",
    $author);

echo $post->getTitle() . $post->getContent() . " Quote from: " .
    $post->getAuthor()->getName();

Even when the quotes’ mapper has been excluded for the sake of brevity, the code’s flow is still pretty easy to understand: it pulls in the first author object (a reference to Bertrand Russell) from the database which gets injected into the quote object. Here the author has been eagerly fetched from the storage before having any chances to process it, which isn’t a cardinal sin by the way.

The purist madman living inside our heads can’t just be tossed aside so easily, though, and keeps murmuring how the author would be better off lazy-loaded. In such a case, we could switch over the proxy instead, and drop it into the application, as follows:

<?php
$author = new AuthorProxy(1, new AuthorMapper($adapter)); 

$post = new Post(
    "About Men",
    "Men are born ignorant, not stupid; they are made stupid by education.",
    $author);

echo $post->getTitle() . $post->getContent() . " Quote from: " .
    $post->getAuthor()->getName();

If you take a close look at the line responsible for creating the post object, you’ll notice that it remains exactly the same as the one from before even though it now takes the proxy and lazy-loads the author from the database. Asides from illustrating how to make use of virtual proxies in a common use case, the example here shows how to keep things copesetic with client code as well. It sticks to the Open/Closed principle and relies entirely on a few segregated interfaces rather than on concrete implementations.

To sum things up: if you’re still wondering if Polymorphism has a place when it comes to creating domain objects that can be swapped up at runtime by virtual proxies (or something along that line), then rest assured it can help you build up scalable, future-proof domain models.

Closing Thoughts

Virtual proxies come in a wide variety of flavors and forms, hence there’s no shortage of options when it comes to exploiting their functionality right out of the box. In many cases, they’re used as placeholders for actual domain objects that are rather expensive to create ahead in time, which makes it possible to load them transparently on request from the persistence layer without poisoning your client code with harmful conditionals.

In the earlier example, a basic proxy was utilized for fetching a simple aggregate from a database, something hopefully instructive in the end, but not entirely in line with the real world. In more realistic situations, domain models are usually much fatter than that and are generally plagued by itteratable collections of domain objects.

Not surprisingly, virtual proxies can be implemented for interplaying with collections as well without much fuss. So, in the next part I’ll show you how to create a collection-targeted proxy class so you can see for yourself if it fits your needs.

Image via imredesiuk / Shutterstock

An Intro to Virtual Proxies

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://www.zfdaily.com David Lukas

    Hi Alejandro, a good read! What if the virtual proxy class extended the original domain object instead of implementing a common interface? (I think I saw such implementation somewhere.) What would be the pros and cons? Wouldn’t that make things simpler in the proxy? E.g. you wouldn’t have to implement all methods of the domain object in the virtual proxy: Let’s have firstName and lastName fields in the domain object together with relevant mutators and accessors. If we also have public function getFullName() {return $this->getFirstName() . $this->getLastName()} in the domain object, we would not have to re-implement this method in the virtual proxy. At first blush it looks like a simpler solution to me so I am sure there must be some shortcomming to it since you have chosen a different approach.
    And here are two pointers for those who like classic books: M. Fowler writes about virtual proxies in PEAA (Lazy Load). Gang of Four have a chapter called Proxy in their Design Patterns.

    • Alex Gervasio

      Hey David,
      Glad you liked the writeup, indeed. Regarding your question, well, honestly nothing should stop you from subclassing the actual domain class and have a neat proxy up and running. In such as case, though, most of the class methods should be overridden, in order to have a nice lazy-loading mechanism doing its stuff behind the scenes (assuming of course, that you’re using a proxy for lazy-loading sets of domain objects from the database).
      While pretty straightforward at first blush, I’m not a big fan of this approach, as it means that the proxy actually doesn’t share implementation with the domain class; only its interface; hence the hierarchy is simply wrong since the “is-a” relationship never holds true. This might lead eventually to mess things up with client code, including notorious and glaring infringements of the Liskov Substitution Principle. Not that I’m claiming that in using “implements” in favor of “extends” you’ll be entirely shielded from incidental LSP breakages. Though, removing clunky subclasses from hierarchies and only deriving subtypes from abstract ones, or directly from plain interfaces may help a lot.
      I hope that answers at least to some extend your questions. Thanks for the feedback.

      • Lukas Zinkl

        Nice introduction to proxies – I did not yet dig into that topic very deep (even though it is what I need just now).

        Ragarding the Implements/Extends problem, I would agree with you.
        The terms themselves already describe the LSP:
        A proxy in no way extends a class but only implements the same public components.
        Also, the class may contain components the proxy does not, which would break the LSP.

        Anyways, I am waiting for the second part. Hopefully, it will not take too long.

        • Alex Gervasio

          Hi Lukas,
          Good to know the article has been instructive. Your thoughts are spot on; lazy-loading proxies expose the same API than of actual domain classes, but in most cases don’t share large chunks of implementation. That’s why it’s a lot preferable to build them up as independent implementers, rather than creating brittle hierarchies, where supertypes/subtypes simply aren’t not interchangeable.
          Thanks for the insights.

  • http://about.me/bruno.skvorc Bruno

    Excellent read, thank you. Very clear and concise and the examples make everything fall into place nicely.

  • Alex Gervasio

    Hi Bruno,
    Thanks for stopping by once again. Nice to hear the intro on proxies has been overall easy to catch. Keep up the good work :-)

    • http://about.me/bruno.skvorc Bruno

      Stopping by? I never left :)
      You’ve actually been a tremendous influence on how I’ve been building my wireframework. After looking through a throng of them I never really quite felt any of them gave me a good out-of-the-box experience with best practices already there, and your tutorials on the domain object model and virtual proxies helped usa great deal in upgrading the knowledge we already had on Service Layers and proper API design. So thanks again!

      • Alex Gervasio

        Good to hear that (it actually makes me blush :). Now seriously, it’s funny to see how easy is to get the feet into the terrain of multi-tiered application design, without having to deal with the oddities and nuances of a bloated framework. Personally, I’ve been working with Domain Models and playing around with DDD structures in general for several years, and never turned back, even with fairly simple applications. With an extendable infrastructure (read implementations depending upon a few nifty interfaces) doing the boilerplate work and a decent DIC in place, (even Pimple fits the bill pretty nicely, though its “array access” nature makes me cranky at times), it’s really straightforward to build up and twist domain models at will without rippling anything weird down to the other layers.

  • René Filip

    Hello Alex,
    I like to thank you so much. You really helped me because I had some trouble with connecting my mapper class with my proxy class.. But this article showed me a nice and clear solution.
    Greetings, René