Spider and web

PHP - Object Oriented Programming

Unlike Javascript, PHP has the necessary syntax and semantics to be a fully object oriented programming language. It has the following abilities:

  • Encapsulation
  • Inheritance
  • Polymorphism (Abstract classes)

Encapsulation

PHP has three visibility levels - public, protected and private. Public means that the variable/method is visible everywhere. Protected means that the variable/method is visible by the class and any inherited classes. Private means the the variable/method is visible by only the class. The protected and private visibility levels enables the programmer to perform information hiding.

It is worth noting that a good programming practice is to have all variables in a class as either private or protected. These variables can then be accessed by accessor methods. This is because:

  • You are able to provide read, write or read/write access
  • Avoid mistakes since all access to the class is through methods
  • You are able to refactor the code in the event of a change super class

It is worth noting that the methods __construct and __clone requires some special consideration as to their visibility levels.

A protected or private constructor will prevent the class from being constructed. This is useful for the singleton or factory patterns. When using this a constructor in this fashion it is worth noting to also offer the clone method the same visibility. A good programming practice is to always write both the construction and clone methods so this mistake is unlikely to occur.

Inheritance

PHP provides inheritance by the use of the extends keyword. Multiple inheritance is not permitted.

Good programming practice is to write both constructors and the clone method. These methods should call the inherited classes constructor/clone method first. This can be achieved by using the parent keyword as shown in this example:

class AnObject
{
  private static $instances = 0;
  private $instance;

  public function __construct()
  {
    echo "Sub object constructed.\n";
    $this->instance = ++self::$instances;
  }

  public function __clone()
  {
    echo "Sub object cloned.\n";
    $this->instance = ++self::$instances;
  }
}

class SubClass
{
  private $subClassObj1;
  private $subClassObj2;

  public function __construct()
  {
    $this->subClassObj1 = new AnObject();
    $this->subClassObj2 = new AnObject();
    echo "Sub class constructed.\n";
  }

  public function __clone()
  {
    $this->subClassObj1 = clone $this->subClassObj1;
    echo "Sub class cloned.\n";
  }
}

class MyCloneable extends SubClass
{
  private $myCloneable1;
  private $myCloneable2;

  public function __construct()
  {
    parent::__construct();
    $this->myCloneable1 = new AnObject();
    $this->myCloneable2 = new AnObject();
    echo "MyCloneable constructed.\n";
  }

  public function __clone()
  {
    parent::__clone();
    $this->myCloneable1 = clone $this->myCloneable1;
    echo "MyCloneable cloned.\n";
  }
}

$obj = new MyCloneable();
echo "\nOriginal\n\n";
print_r($obj);
$obj = clone $obj;
echo "\nCloned\n\n";
print_r($obj);

Polymorphism (Abstract classes/Interfaces)

Polymorphism is when two or more classes implement the same function(s) so that they provide the same interface. PHP overcomes the diamond problem by not allowing multiple inheritance and only allowing the implementation of multiple interfaces.

To implement polymorphism in PHP you have two choices to ensure that all the necessary functions are implemented and you can use the type declarations for the formal parameters:

  • Abstract classes - This will allow you to partially implement some of the class
  • Interfaces - This will enable a class to implement multiple interfaces

Below is examples of both methodologies to implement a cat and dog objects that have the two functions Name and Talk

Abstract classes

The code below shows how the scenario can be implemented using abstract classes. With this method it is possible to implement part of the class and also name variables. However you can only use one abstract class to produce further sub-classes:

abstract class Animal
{
  protected $name;
  public function Name() { return $this->name; }

  abstract function Talk();
}

class Cat extends Animal
{
  public function __construct($name) { $this->name = $name; }
  public function Talk() { return 'Meow'; }
}

class Dog extends Animal
{
  public function __construct($name) { $this->name = $name; }
  public function Talk() { return 'Woof'; }
}

Interfaces

With interfaces you can overcome the problem of only being able to implement one interface but with the penalty that the interface cannot implement any functionality.

The example below demonstrates how this is achieved in PHP

interface Animal
{
  public function Name();
  public function Talk();
}

class Cat implements Animal
{
  protected $name;
  public function __construct($name) { $this->name = $name; }

  public function Name() { return $this->name; }
  public function Talk() { return 'Meow'; }
}

class Dog implements Animal
{
  protected $name;
  public function __construct($name) { $this->name = $name; }

  public function Name() { return $this->name; }
  public function Talk() { return 'Woof'; }
}

Finally

It is a good idea to document your classes. I recommend Doxygen as it produces usable documentation taken from the comments in your code along with the structure of your class hierarchies.