Prototypal Inheritance In PHP post

Generally, programming languages follow one of two types of inheritance patterns. These patterns describe how objects are defined, and how properties and methods are composed between them.

Classical Inheritance

Likely the most familiar pattern is classical inheritance, which is how PHP and many other languages are designed. Briefly, classical inheritance involves keywords like classes (abstract, final), objects, interfaces, and methods with special usage, like constructors and destructors. Classes extend other classes (single or multiple inheritance -- PHP implements single inheritance).

<?php

class vehicle {
    protected $engine = null;
    protected $milesTravelled = 0;
    protected $doorCount = 0;
}

class truck extends vehicle {
    // $engine, $milesTravelled, and $doorCount are inherited from vehicle
    protected $doorCount = 2;
    protected $hasTailHitch = true;
}

class motorcycle extends vehicle {
    // $engine, $milesTravelled, and $doorCount are inherited from vehicle
    protected $doorCount = 0;
}

$vehicle = new vehicle();
$truck = new truck();
$motorcycle = new motorcycle();

Prototypal Inheritance

The lesser known and used of the two patterns is prototypal, which is how Javascript handles inheritance, for example. Instead of classes and interfaces, there are only objects. Objects are dynamically assigned properties and methods, and new objects (children) inherit the properties and methods of the parent object, through the parent's prototype. The prototype is a reference to a set of properties and methods, and because it is a reference any changes are reflected across child objects sharing the same prototype.

<?php

$vehicle = new stdClass();
$vehicle->engine = null;
$vehicle->milesTravelled = 0;
$vehicle->doorCount = 0;

$truck = new $vehicle(); // doesn't work
$truck->doorCount = 2;
$truck->hasTailHitch = true;

$motorcycle = new $vehicle(); // doesn't work
$motorcycle->doorCount = 0;

Whoa, wait a minute. There isn't any structure to this code. This is a very dynamic and powerful concept that radically simplifies things. The only problem now is that the lines where we instantiate our children (truck and motorcycle) will not actually return the right results, since PHP is class-based and all (a runtime error will probably trigger).

Making Invocation Work

As a dynamic language, PHP is well suited to the protypal pattern, and has native support for assigning new properties (and methods as of 5.3+) to objects at run time, so most of the hard work has already been done for us. The only missing piece is native syntax for the invocation lines that create child objects. So what does it take to make those lines work? With a slight syntax tweak, turns out not much, actually:

<?php

public function __invoke() {
    return new self($this);
}

/**
 * In a hypothetical class, defining this magic method will allow the object to be invoked,
 * so instead of:
 *
 * $truck = new $vehicle();
 *
 * The syntax becomes:
 *
 * $truck = $vehicle();
 */

If we create a class and define its magic __invoke() method to return a new instance of itself, our object invocation syntax now works. In order to implement prototypal inheritance more completely, a little more work is involved, however, a well-formatted solution is still less than 100 LOC.

Categories: features