Object-orientated development: a lesson in PHP5

PHP has been given a major stabbing and bashing in the last few years. Mainly due to inconsistency, non native support for UTF8 and the fact that only from v5 has it been “object-orientated capable”. However, PHP just works. Out of the box. It delivers on a promise to produce dynamic web pages.

Below is a best practice guide on using PHP in an Object Orientated (OO) manner.

Why Object-Orientated (OO) Programming

  • Objects can store data internally. Therefore variables don’t need to be passed from function to function like in procedural programming.
  • Better organization, portability and reuse of code. You can place common functionality in a Class inside its own separate file using a common naming convention that can be reused in other applications by using an include. Think DRY (Don’t Repeat Yourself) principle.
  • Maintainability is improved. Code is easier to spot and alter in the 1st place. Another DRY principle.
  • Gets you building sites using MVC (Model-view-controller) framework like CodeIgniter, Zend Framework et al.. which are built around PHP5 OO and enforce good coding standards, practices and patterns.
  • Allows you to experience Convention over Configuration (CoC) principles in your MVC application.

Ok, so hopefully you are now convinced that OO is the way forward.

Object-Orientated (OO) Paradigms

Before I begin, let’s cover some basics of OO. That is, a Class represents an object, with associated methods and variables. Therefore all the functionality we will build will be wrapped in Classes. Think of them as blueprints for an object.

PHP treats objects in the same way as references or handles, meaning that each variable contains an object reference rather than a copy of the entire object. Note, since objects can be passed as arguments to a function they are by default “copied” unless you specify the argument as a reference variable &$variable.

Here’s a run down of some fundamental OO Paradigms you should be considering and even using to write kick ass OO code.

These paradigms are all used in my sample code below.

Inheritance

Inheritance extends a Class (base) to bring additional functionally to your Class (child). This allows you to create a hierarchy of interlinked classes. In PHP5 only 1 Class can be inherited.

For example, if we have a parent Class “Dog” which holds common Dog like behavior like “bark” we can extend that into our child Classes say “Poodle”, “Husky” etc… Therefore Poodle and Husky can both inherit the same method called “bark” which specifies the shared functionality without having to repeat it across other children Classes.

More on inheritance is covered here: http://www.php.net/manual/en/language.oop5.inheritance.php

Constructor and destructor methods

These are methods called upon creation or destruction of Class object. Typically if you want to initialize a certain property on the creation of an object or cleanup post use.

More on these methods is covered here: http://php.net/manual/en/language.oop5.decon.php

Member privacy (visibility)

This defines who has access to members and methods.

<strong opinion>I believe visibility is a lot of hog wash in PHP. PHP was designed by Rasmus Lerdorf for “web development to produce dynamic web pages” (ref: wiki). Member privacy is largely important when building components that are used by 3rd parties. Like something you would do in Java/C++ with dll/com objects. There is absolutely no good reason I know of why you’d want to hide certain Class functionality from your own developers. Use Interfaces if you must “guide” them on what they can and cannot use. Python got this right!</strong opinion>

More on member privacy is covered here: http://www.php.net/manual/en/language.oop5.visibility.php

Encapsulation

Encapsulation is a reference to well-defined interface to a set of functions in a way which hides their internal workings. The benefit here is it can reduce complexity for another developer by not exposing the whole inner workings of a class. This is achieved using member privacy (discussed above).

More on encapsulation here: http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming)

Interfaces

Allows you to specify a Class templates for other developers to showing which public methods can be implemented without exposing how these methods are handled. Only methods can be declared in an Interface, not variables. More than 1 Interface can be extended in a Class.

More on interfaces can be found here: http://en.wikipedia.org/wiki/Object-oriented_user_interface

Overloading

Overloading allows you to dynamically create or extend public properties or methods. These dynamic entities are processed via magic methods.

More on overloading here: http://www.php.net/manual/en/language.oop5.overloading.php

Patterns

Factory: The Factory pattern allows for the instantiation of objects at runtime. It is called a Factory Pattern since it is responsible for “manufacturing” an object. A Parameterized Factory receives the name of the class to instantiate as argument. And;
Singleton: The Singleton ensures that there can be only one instance of a Class and provides a global access point to that instance. Often implied in Database Classes, Loggers, Front Controllers or Request and Response objects.

More on Patterns here: http://www.php.net/manual/en/language.oop5.patterns.php

Now let’s look at how all of this would fit into code.

Note that I have tried to fit all these practices into the 1 sample of code below. Read the internal comments I put in to understand what is going on. Any mistakes or questions please use the comments section below to let me know.

The CODE – in PHP

// Interface implementation
interface BaseInterface
{
	function method0();
}

// Class definition with keyword "implements" to implement BaseInterface interface above.
class BaseClass implements BaseInterface
{
	// property declaration
	private $attribute3 = "This is PHP5";

	// method declaration, by default this is public
	function method0() {
		print "This is Method0";
	}
}

// Always use Upper camel case naming notation for class names
// Inheritance is achieved by using the "extends" keyword with class you want to extend.
class ChildClass extends BaseClass
{
	// This variable is accessible without needing an instantiation of the class.
	public static $attribute0 = "Yes I'm visible";

	// This variable can only be accessed within this class
	// This is also an encapsulated attribute never exposed outside the class.
	private $attribute1;

	// This variable can be accessed outside this class
	public $attribute2;

	// Note the above visibility of the attributes.
	// There are 3 types and can be accessed - public (everywhere), protected (class & inherited) or private (only by class).

	// A class can only have 1 constructor
	// Suitable for any initialization that the object may need before it is used.
	function __construct($arg1, $arg2, …) {
		// Use operator arrow to access class variable
		// Note the lack of $ in front of attribute1. This is valid and also a common mistake among newbies.
		$this->attribute1 = "ABC";
	}

	// A class can only have 1 destructor
	// Called when the object is explicitly destroyed.
	private function __destructor($arg1, $arg2, …) {
		$this->$attribute1 = "";
	}

	// This method has no "visibility" declared so by default it becomes "public".
	function method1() {
		print "This is Method1";

		// Access to base class method / attribute using parent::
		// This call docent automatically evoke base class contractor / desconstructor unless called via parent::
		print "From BaseClass: " . parent::$attribute3;
	}

	// "final" stops this method from being overridden.
	final public function method2($a) {
		$this->attribute2 = $a;

		// Displays to screen the "encapsulated" attribute
		print $this->attribute1;
	}
}

// Accessing static attribute without instantiating a class
print ChildClass::$attribute0;	// Output: 'Yes I'm visible'

// Creating new instances of the child class
// Note that since ChildClass has arguments in the constructor function those need to be passed during this object's instantiation.
$foo = new ChildClass(1, 2, ...);
$bar = new BaseClass();
// Like functions, this instantiated object will have its own "class scope" so any method/variable is different to say $bar object.
$soap = new BaseClass();

// Accessing object members
$foo->attribute1;		// Output: 'ABC'
$foo->method1();		// Output: 'This is PHP5'
$bar = method0();		// Output: 'This is Method0'

I think that is enough to digest for now. If you want to read more on Object-Orientated PHP5 I recommend you visit PHP.NET here: http://www.php.net/manual/en/language.oop5.basic.php

Hope this post has shed more light on OO in PHP and you are ready to crank out some clean and usable OO code.

~ Ernest