Constructors and Breaking the Liskov Substitution Principle

Tweet

At the risk of being targeted by the PHP hate-mongers, I must confess that I’m pretty comfortable with PHP’s object model. I’m not that naïve to claim it’s a full-blown model exposing all the bells and whistles of other “fatter” players, such as C++ and Java, but despite of all its quirks, PHP delivers what it promises at face value. I would say however that the model is notoriously permissive considering the relaxed constraints it imposes when it comes to defining userland interfaces.

One issue with the model’s “forgiveness” is that one fine day you may wake up in a whimsical mood and specify a constructor inside an interface just because you can, without a twinge of guilt. If you think this through, the existence of a constructor as part of an interface is pretty pointless. First off, every time you define a contract, you’re actually abstracting away the behavior of the concrete implementations and leaving out of the picture how they must be assembled down the road. Second, how in the world you can get client code consuming a constructor once the implementers have been instantiated? There’s no parallel universe in which you can do such things unless without sloppily polluting consumers with a bunch of new operators, which should live and breathe somewhere else according to the “isolate application logic from object construction” mantra.

Rants aside, the morale of the story can be boiled down to the following: “Object construction is not part of the contract honored by its implementers”.

It’s easier to grasp concepts by example rather than reading dull theory, so in this article I’ll be demonstrating from a practical standpoint how the implementation of different constructors down the same hierarchy isn’t a violation of the Liskov Substitution Principle, which is a reason why you shouldn’t fall into the temptation of tainting your interfaces with constructors.

The Myth of LSP Breakage

I guess I’ve already made a valid point with regard to avoiding constructors in interfaces, a process that certainly helps to generate contracts that describe and prescribe the behavior of certain object types (a.k.a. Subtype Polymorphism) but not how to create the objects in question. It might be incidentally harder, however, to understand why overriding a parent constructor in a subclass, or eventually implementing a brand new one doesn’t violates the LSP.

Let’s say we need to create a PDO adapter just by hanging a lightweight subclass from the native PDO. The adapter’s contract, along with the corresponding implementation, could look as follows:

<?php
namespace LibraryDatabase;

interface DatabaseAdapterInterface
{     
    public function executeQuery($sql, array $parameters = array());
    public function select($table, array $bind, $operator = "AND");
    public function insert($table, array $bind);
    public function update($table, array $bind, $where = "");
    public function delete($table, $where = "");
}
<?php
namespace LibraryDatabase;

class PdoAdapter extends PDO implements DatabaseAdapterInterface
{
    private $statement;   
    
    public function __construct($dsn, $username = null, $password = null, array $options = array()) {
        if (!extension_loaded("pdo")) {
            throw new InvalidArgumentException(
                "The adapter needs the PDO extension to be loaded.");
        }
        if (!is_string($dsn) || empty($dsn)) {
            throw new InvalidArgumentException("The DSN is invalid.");
        }
        parent::__construct($dsn, $username, $password, $options);
        $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $this->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    }
    
    // Prepare and execute an SQL statement
    public function executeQuery($sql, array $parameters = array()) {
        try {
            $this->statement = $this->prepare($sql);
            $this->statement->execute($parameters);
            $this->statement->setFetchMode(PDO::FETCH_OBJ);
            return $this->statement;
        }
        catch (PDOException $e) {
            throw new RunTimeException($e->getMessage());
        }
    }
    
    // Prepare and execute a SELECT statement
    public function select($table, array $bind = array(), $operator = "AND") {
        if ($bind) {
            $where = array();
            foreach ($bind as $col => $value) {
                unset($bind[$col]);
                $bind[":" . $col] = $value;
                $where[] = $col . " = :" . $col;
            }
        }
        $sql = "SELECT * FROM " . $table 
             . (($bind) ? " WHERE " 
             . implode(" " . $operator . " ", $where) : " ");
        return $this->executeQuery($sql, $bind);
    }
    
    // Prepare and execute an INSERT statement
    public function insert($table, array $bind) {
        $cols = implode(", ", array_keys($bind));
        $values = implode(", :", array_keys($bind));
        foreach ($bind as $col => $value) {
            unset($bind[$col]);
            $bind[":" . $col] = $value;
        }
        $sql = "INSERT INTO " . $table 
             . " (" . $cols . ")  VALUES (:" . $values . ")";
        $this->executeQuery($sql, $bind);
        return $this->lastInsertId();
    }
    
    // Prepare and execute an UPDATE statement
    public function update($table, array $bind, $where = "") {
        $set = array();
        foreach ($bind as $col => $value) {
            unset($bind[$col]);
            $bind[":" . $col] = $value;
            $set[] = $col . " = :" . $col;
        }
        $sql = "UPDATE " . $table . " SET " . implode(", ", $set) 
             . (($where) ? " WHERE " . $where : " ");
        return $this->executeQuery($sql, $bind)->rowCount();
    }
    
    // Prepare and execute a DELETE statement
    public function delete($table, $where = "") {
        $sql = "DELETE FROM " . $table 
             . (($where) ? " WHERE " . $where : " ");
        return $this->executeQuery($sql)->rowCount();
    }
}

The batch of tasks performed by the PdoAdapter class are indeed straightforward, limited to running a few prepared queries via its executeQuery() method and shooting some CRUD operations against a given table. The most relevant detail to highlight here is how the adapter overrides its parent’s constructor in order to do some checks and see if the PDO extension has been installed before starting consuming it.

Here’s how we’d get the adapter up and running:

<?php
use LibraryLoaderAutoloader,
    LibraryDatabasePdoAdapter;
  
require_once __DIR__ . "/Library/Loader/Autoloader.php";
$autoloader = new Autoloader;
$autoloader->register();
    
$adapter = new PdoAdapter("mysql:dbname=test", "myusername", "mypassword");
   
$stmt = $adapter->prepare("SELECT * FROM users");

$stmt->execute();

$users = $stmt->fetchAll(PDO::FETCH_OBJ);

foreach ($users as $user) {
    echo $user->name . " " . $user->email . "<br>";
}

I’m intentionally avoiding the adapter’s executeQuery() method and instead appealing to the native execute() method to pull in a few users from the database. At first blush this all seems to be pretty boring boilerplate stuff that should be skipped over for more interesting things… but bear with me because indeed there’s a tiny catch here worth stressing. Even considering that the adapter effectively implements a different constructor from the default one provided by PDO, the contract it agrees with client code is neatly maintained from top to bottom. In short, this means that having disparate constructor implementations in a base type and in a subtype by no means infringes the LSP substitutability rules as long as the contract exposed by the two classes is properly honored.

Logically, this can be seen more clearly if we switch the previous script over to a native PDO instance rather than consuming the adapter:

<?php
$adapter = new PDO("mysql:dbname=test", "myusername", "mypassword");

$stmt = $adapter->prepare("SELECT * FROM users");

$stmt->execute();

$users = $stmt->fetchAll(PDO::FETCH_OBJ);

foreach ($users as $user) {
    echo $user->name . " " . $user->email . "<br>";
}

The fact of having a hierarchy of classes, even a very elemental one, where the subtypes are constructed differently than the base types has literally nothing to do with breaking the desired substitutability that’s actively promoted by the LSP.

You might argue that the signatures of the adapter and the native PDO look pretty much the same, and that’s why substitutability is in this case preserved so well. But it’s really easy to refute an argument like this. For instance, I could take a more pragmatic approach and refactor the adapter’s constructor so that it can accept an array of named connection arguments:

<?php
namespace LibraryDatabase;

class PdoAdapter extends PDO implements DatabaseAdapterInterface
{
    private $statement;   

    public function __construct(array $config = array()) {
        if (!extension_loaded("pdo")) {
            throw new InvalidArgumentException(
                "The adapter needs the PDO extension to be loaded.");
        }
        if (!isset($config["dsn"]) || !is_string($config["dsn"])) {
             throw new InvalidArgumentException(
                "The DSN has not been specified or is invalid.");
        }
        $username = $password = $options = null;
        extract($config);
        parent::__construct($dsn, $username, $password, $options);
        $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $this->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    }
    
    // the same implementation goes here
}

At this point the adapter’s constructor is a pretty different creature whose signature and implementation neatly accommodate an array of connection parameters instead of digesting plain scalars. With such a drastic refactoring in place, one might take for granted that isn’t possible to swap out at runtime an instance of the adapter with a native PDO one anymore. Rush judgments tend to be dangerous, something that the following snippet puts in evidence:

<?php
$adapter = new PdoAdapter(array(
    "dsn"      => "mysql:dbname=test", 
    "username" => "myusername", 
    "password" => "mypassword"
));

$stmt = $adapter->prepare("SELECT * FROM users");

$stmt->execute();

$users = $stmt->fetchAll(PDO::FETCH_OBJ);

foreach ($users as $user) {
    echo $user->name . " " . $user->email . "<br>";
}

Even though instantiating an instance of the adapter is now quite a different process, the client code remains entirely agnostic about this change in the contract it consumes remains the same!

Still, if you feel a pinch of skepticism and think the example falls short when it comes to demonstrating the interchangeability between types of a given hierarchy, look at the following which refactors even more drastically the constructor and supplies the connection arguments via a naive DTO (Data Transfer Object):

<?php
namespace LibraryDatabase;

interface ConnectionDefinitionInterface
{
    public function getDsn();
    public function getUserName();
    public function getPassword();
    public function getOptions();
}
<?php
namespace LibraryDatabase;

class ConnectionDefinition implements ConnectionDefinitionInterface
{
    private $dsn;
    private $username;
    private $password;
    private $options = array();

    public function __construct($dsn, $username = null, $password = null, array $options = array()) {  
        if (!is_string($dsn) || empty($dsn)) {
            throw new InvalidArgumentException("The DSN is invalid.");
        }
        $this->dsn = $dsn;
        $this->username = $username;
        $this->password = $password;
        $this->options = $options;
    }
    
    public function getDsn() {
        return $this->dsn;
    }
    
    public function getUserName() {
        return $this->username;
    }
    
    public function getPassword() {
        return $this->password;
    }
    
    public function getOptions() {
        return $this->options;
    }
}
<?php
namespace LibraryDatabase;

class PdoAdapter extends PDO implements DatabaseAdapterInterface
{
    private $statement;   
    
    public function __construct(ConnectionDefinitionInterface $connectionDefinition) {
        if (!extension_loaded("pdo")) {
            throw new InvalidArgumentException(
                "The adapter needs the PDO extension to be loaded.");
        }
        parent::__construct(
            $connectionDefinition->getDsn(), 
            $connectionDefinition->getUserName(), 
            $connectionDefinition->getPassword(), 
            $connectionDefinition->getOptions()
        );
        $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $this->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    }

    // the same implementation goes here
}

While it’s fair to admit that DTOs don’t have a prolific existence in the PHP world (though some popular frameworks like Zend Framework 2 and Simfony 2 use them ubiquitously), in this case I appealed to a simple one to pass a set of connection arguments to the adapter’s constructor. The radical change, for obvious reasons, is going to ripple artifacts toward the code responsible for instantiating the adapter, be it a DIC, a low-level factory, or any other independent mechanism along that line that doesn’t interfere explicitly with application logic:

<?php
$adapter = new PdoAdapter(
    new ConnectionDefinition("mysql:dbname=test", "myusername", "mypassword")
);

As long as the adapter’s contract remains untouched along the way, it’s possible to interchange an instance of the adapter with a PDO one and client code won’t pitch a single compliant.

Though this example might be somewhat overkill when it comes to pushing PDO functionality inside the boundaries of a slim wrapper, it does an excellent job at showing the flagrant LSP breakages that are easily found in the wild occur because of other reasons, which I dare to claim aren’t even related to the “flaws” of the base type/subtype construction schema.

Closing Remarks

The mantra has been said over and over, but it’s worth stressing it once again: providing a certain programming principle or pattern with a dogmatic connotation which must be blindly fulfilled is something almost as harmful as not using those patterns and principles at all, hence letting the chaos of pragmatism dramatically rot the quality of a system.

Aside from attempting to demystify constructors as one of the root causes of potential LSP infringements, my argument against including constructors in interfaces certainly isn’t meant to be dogma. But being aware of the consequences of this sort of “construction-restrictive” contracts just because PHP’s object model is relaxed in that aspect might help to mitigate the proliferation of this inflexible, pointless practice.

Image via Fotolia

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://mwop.net/ Matthew Weier O’Phinney

    I personally avoid constructors in interfaces because they restrict a number of useful design patterns. In particular, patterns like Decorator, Proxy, and Visitor often need to consume an existing object, and then proxy methods. The easiest way to accomplish this is for them to accept the object via the constructor, and then implement the common interface. The problem, then, is if the interface defines a constructor, you limit these sorts of possibilities.

    If the instantiation of an object needs to be defined via the interface, define a static factory method instead, and have that return the new instance. Because it’s part of the object itself, you can even call on protected or private members within the object body.

    • Alex Gervasio

      Hey Matt,
      Thanks for the feedback indeed. Well, I guess the reasons you mention above make even a stronger point against the definition of constructors in interfaces. As it was pointed out in the article, IMO how an object is constructed should never been part of the contract it implements. Contracts are aimed at abstracting behavior, but this certainly shouldn’t include how to assemble their implementers.
      And yes, even when I have to admit I’m not a big fan of static methods in general, I agree with you with the idea of including a static factory method inside an interface, in those cases where the instantiation of the object needs to be explicitly defined. Again, thanks for the insights :)

  • http://customscripts.co.za Pierre

    Very nice article with some very valid points. I also believe that a constructor should never be defined in an interface. Even with the possibility of a static singleton, it limits the parameters that you can use and the way you can extend a class.

    On a side note, you can’t extend the PDO class, and then check if the extension is indeed loaded in the constructor. PHP will complain immediately that the PDO class doesn’t exist even before you get a chance to execute the constructor.

    • Alex Gervasio

      Hi Pierre,
      Glad to know the post has been overall informative, so thanks for the positive comments. Totally agreed in the sense of avoiding to define constructors in interfaces, due to the batch of reasons pointed out through the article, plus the ones posted by Matt and you. In regards to the impossibility to check if the pdo extension has been loaded in a PDO subclass’ constructor, well honestly I never got a compliant from PHP (5.4). I ran some tests while I was writing down the article but I could never recreate such a scenario.