OOP in PHP

Target Audience:

Beginners to Object Oriented Programing who use PHP.  Anyone looking for a detailed explanation of OOP Programming in PHP.

Languages Used:

PHP 5+

Related Material:

PHP Manual – Class
Class Design in PHP

Introduction:

Object Oriented Programming is a technique adapted first mainly by video game designers and then later picked up by traditional software designers and even web application development using languages such as PHP, JSP, and ASP .NET.  Procedural programmers find the transition to OOP one of the most challenging of their careers because it completely changes the way you have to think about your data, and the operations your program performs.

I was one of those old school programmers that struggled to wrap my head around what I discovered was actually a very simple concept.  I am hoping that my experience will help me explain to you how you can transition from a procedural style to OOP.  But first, to begin using OOP you will need to understand the following;

  • Classes
  • Instantiation aka Objects
  • Encapsulation
  • Inheritance

Two other concepts in OOP that we will not talk about in this post but will explain in grater detail later are;

  • Abstract and Static Classes
  • Polymorphism

Classes: (see also Class Design in PHP)

Classes are the blueprints for objects.   When using OOP you need to start learning to think about your program or application as if it consisted of real world things doing real world actions.  Classes are where you define the characteristics and abilities of those things.

Great you say, what does that mean?  To understand you need to back away from project and look at from the outside.  The best way to start is to write down an explanation of your program, what it does, how it works, and how it is interacted with.  For a big program this could take a lot of time, but that is ok you will thank your self later.

We are going to use a very simple example.

This program is a zoo.  When the program starts three animals will be shown to the user. A white cat, a brown dog and a gray koala.  The user will be able to select an animal and click speak to make that animal speak.  When selected the cat will say ‘meow’, the dog will say ‘woof’ and the koala will say ‘jolly good day sir’.

The first thing we need to do is identify all the things we need for our program.  The best way to do this is simply list all the nouns in our sentence above.

program, zoo, animal(s), user, cat, dog, koala.

Next we need to eliminate some of the obvious.   ‘program’ and ‘user’ are not included because the user is outside the program, and the program is what all our classes will make up.

zoo, animal(s), car,dog, koala.

You are probably wondering why we have animal(s) in our list when the cat, dog and koala are our animals.  The answer is a concept we call Inheritance, which we will cover more on later.   For now though we will just ignore animals, understanding that the cat, dog and koala are our animals.

The next thing we need to do is locate all of our objects characteristics.  This is done by going back to our written out explanation and finding all the adjectives that describe our things.

This program is a zoo.  When the program starts three animal(s) will be shown to the user. A white cat, a brown dog and a gray koala.  The user will be able to select an animal and click speak to make that animal speak.  When selected the cat will say ‘meow’, the dog will say ‘woof’ and the koala will say ‘jolly good day sir’.

cat – {white}

dog – {brown}

koala – {grey}

After locating all of your things characteristics we just need to locate the actions they need to perform.  This is done by locating all the verbs attached to our thing.

This program is a zoo.  When the program starts three animal(s) will be shown to the user. A white cat, a brown dog and a gray koala.  The user will be able to select an animal and click ‘speak’ to make that animal speak.  When selected the cat will say ‘meow’, the dog will say ‘woof’ and the koala will say ‘jolly good day sir’.

zoo – {} (shown)

cat – {white}  (say)

dog – {brown} (say)

koala – {grey} (say)

Now look at our actions.  To make things make a little more sence we need to change our wording around just a little bit.  Starting with zoo; the zoo needs to ‘show’ three animals.  So lets change ‘shown’ to show.  Next our animals will all ‘say’ something when told to ‘speak’.  Since we know that the cat, dog and koala are all animals, where we say ‘make that animal speak’ we know it refers to them.   When told to speak those animals will say something.  So instead of say we are going to change all of them to speak.

zoo – {} (show)

cat – {white}  (speak)

dog – {brown} (speak)

koala – {grey} (speak)

This process can take a little thinking and judgment on your part to get the right wording, but the important thing is that all your actions are in fact represented by your classes.   To take the information we have collected above and now represent it in code see my code example below.  If you are experienced in the syntax already try and build these classes on your own first.  If you are completely new to the syntax I encourage you to read see Class Design in PHP.

Code:

class Zoo
{
    var $_animals = Array();

    function Show()
    {
	echo "<h2>Animals in the zoo:</h2>";

	foreach ($this->_animals as $animal)
	{
 	    echo "<a href='?action=speak&animal=" . get_class($animal)
                . "'>" . get_class($animal) . "</a><br />" ;
        }
    }

    function __construct()
    {
 	$this->_animals["Cat"] = new Cat("White");
	$this->_animals["Dog"] = new Dog("Brown");
	$this->_animals["Koala"] = new Koala("Grey");
    }
}

class Cat
{
    var $_color;

    function Speak()
    {
 	return "Meow";
    }

    function __construct($color)
    {
        $this->_color = $color;
    }
}

class Dog
{
    var $_color;

    function Speak()
    {
	return "Woof";
    }

    function __construct($color)
    {
	$this->_color = $color;
    }
}

class Koala
{
    var $_color;

    function Speak()
    {
 	return "Jolly good day sir";
    }

    function __construct($color)
    {
	$this->_color = $color;
    }
}

$zoo = new Zoo();

if (isSet($_REQUEST['action']))
{
    $animal = $zoo->_animals[$_REQUEST['animal']];

    echo "The " $animal->_color . " " . get_class($animal)
        . " said '" . $animal->Speak() . "'";
}

$zoo->Show();

Instantiation aka Objects:

Instantiation is the process of creating a new instance of an object from a class.  With all those big words it sounds scary but really it is the simplest concept you need to learn.  When you design a class what you are doing is defining the blueprints for your objects.   That code by itself does nothing without your objects.  (Static classes are an exception that we will discuss later).

Once you instantiate your objects, all that objects characteristics and actions are stored inside the object, and can be used by your program.   The new keyword in PHP is how we make this happen.  Look at the bottom of our code example above.  See how we are create a new instance of our Zoo class.

$zoo = new Zoo();

Now that we have an instance of our zoo we can look at the zoo’s $_animals and call the zoo’s Show() method.  This is done using a special operator   ->  after the variable storing our object.

$animals = $zoo->_animals;

$zoo->Show();

The only other thing you really need to know about instantiation is that you can have more then one instances of the same class at the same time.  Each instance could contain completely different values for their characteristics.  Meaning one of our zoo’s could have a white cat while the other one has a black cat.   In our example, to do this, you would have change the constructor method in the zoo class and use a different way for adding animals to the zoo.  See if you can do this yourself.

Encapsulation:

Encapsulation is the process of abstracting your objects characteristics or fields from anything using that object.  The purpose of doing this is so that you can strictly control how your data is accessed, manipulated, and even populated.  By default all of our fields and methods in our class are what we call ‘public’, meaning they can all be accessed from instances of our class.  $_animals is a public field and can be accessed from our Zoo instances.

This works great because we can easily grab our animals from our zoo and get information about them.  The problem with this is, we can now also overwrite the value of the animals in our zoo since we can access it.

$zoo->_animals = "Hello World";

Now suddenly our animals are not animals at all, it is a simple string.  This will lead to all kinds of problems in our program if this happens.  For one, $_animals is expected to be an array so as soon as we try to access a value in it as an array we will get an error.  In addition, our program expects to be able to pull objects from the array and access their methods for speak().  To prevent this from happening we use encapsulation to first hide our $_animals filed from everyone else, then we will provide a new way to access it using our rules.

The keywords you will use with Encapsulation our ‘pubic‘, ‘private‘, and ‘protected‘.   Like mentioned above, all fields and class members are public be default.  It is still a good idea to label your public fields with the public keyword however, so that your code is easier to read and for others to understand.

Private means, this field can only be used inside the class and by methods of the class.  Meaning, if I set $_animals to private I can no longer access it from our objects instance of $zoo, but I can still use it inside our classes code.  This will keep people from being able to set $_animals to a string value.

class Zoo
{
    private $_animals = Array();
    ...
}

Now if we try to access $_animals from our $zoo instance it would result in an error.  This is good, it now prevents people from changing our $_animals value to something other then an array of Animals.  Next we need to provide a way for the class to share it’s $_animals with the world.  To do this we are going to create a function inside our class that returns the value of our animals.

public function Animals()
{
    return $_animals;
}

Now we have provided a way for us to get our animals out of the zoo.   If we call our public Animals() function from our $zoo instance, it will return our array of animals safely saved in our class, however there is no way for people to change the value of our $_animals field to anything that is not an array of Animals.

$zoo = new Zoo();
$animals = $zoo->Animals();

Now things are looking a little more stable.  There is still one problem though. We have no way of adding animals to our zoo.  We hid our $_animals field from the outside world so that it could not be changed to something other then an array of Animals.   We were able to get the value saved in that field by creating a public function that returns it.  This means we can also use a function to create  a method to add new animals to our zoo.

public function AddAnimal($animal)
{
    if(get_class($animal) != "Cat"
        && get_class($animal) != "Dog"
        && get_class($animal) != "Koala")
        {
            throw new Exception("$animal is not an allowed Animal type");
	}

    $this->_animals[] = $animal;
}

Now we can add more animals to our zoo if we want to, and we know that the animals they add will either be a Cat, Dog, or Koala, all of which are animal objects.  Now there is no chance that the value of our $_animals field can ever be set to anything that is not an array of animals.

This whole process is an example of Encapsulation.  We have encapsulated our $_animals field in this example.  It is generally a good idea to encapsulate all your fields, even if you want to allow complete access to them.  This is not only good coding practice but it also makes your code more consistent and easier to follow.

Inheritance:

Inheritance in OOP terms is the process of a child class taking on the characteristics of it’s parent or base class.  Meaning any of the characteristics such as fields or functions all are inherited by the child that extends it.  This is used most often when you have a group of objects that share similar characteristics but have some uniqueness that separates them.

We happen to have this situation in our Zoo application.  All of our animals share a characteristic of color. They all also can be added to the $_animals[] field.   That and the biggest commonality of them all is they are all ‘Animals’   Remember our original sentence.  We removed Animals from the sentence since the ‘Cat’, ‘Dog’, and ‘Koala’ were all Animals.  This is where we get to add it back in.

To add animals back into our program from our sentence we simply need to make a new Animal class.  This class will contain all the common characteristics and actions of the classes that will need to inherit it.  In this case our common field is $_color, and our common action is Speak().

class Animal
{
    private $_color;
    function Speak()
    {
 	return "Well, I Say!";
    }
    function __construct($color)
    {
	$this->_color = $color;
    }
}

With this code we could now create a generic animal object that has a color and can speak.  This by itself is no big accomplishment however we can now set all of our animal type objects to inherit  it’s characteristics from the animal class.  To do this we simply add the extends keyword to the end of our class names and the name of the class it extends.

class Cat extends Animal
{

}

Now with this code when we create a new Cat object it will have all the same characteristics as a generic Animal.  Since those fields and functions are inherited we don’t need to redefine them in the child class.  This leaves our Cat class pretty bare, but with the exact same functionality it had before.

There is only one problem.  Now when the cat is asked to speak it will invoke it’s parent’s Speak function that it inherited and say “Well, I Say!” instead of “Meow”.  This is where the concept of overwriting comes into play.  Overwriting is the process of replacing  an objects inherited characteristic with one of it’s own.   We can use this technique to overwrite the Animals Speak function with one specifically for our cat.

class Cat extends Animal
{
    function Speak()
    {
 	return "Meow";
    }
}

Now our cat will use it’s own Speak function when evoked from it’s instance.   Well why would go through the trouble of inheriting characteristics just to overwrite them?  The best reason is because their our still some other charictoristics, such as $_color that don’t need to be overwritten and will work for all animals.  This saves us from having to write all that same code over and over and over.

It also provides us a few other advantages.  Look at our AddAnimal() function in our Zoo class.  Currently it is only allowing us to add Cat, Dog and Koala objects.  In fact we can’t even add our newly created Animal object without going in add adding a condition for it in our if statement.  Imagine how many conditions we could have if our zoo ever expanded?  Not to mention the pain in the butt it would be to go back and change the code every time we wanted to add a new animal.

By having all our objects inherit from the Animal class we can now perform a more generic check against our new animals before we allow them in our Zoo.   This is done by using PHP’s is_subclass_of() function.  This function will return true if the passed in object is of or has directly or indirectly derived from the Animal class.  This means we could even create a new class called Panther that inherited from Cat that inherited from Animal.  No matter how many times we extend out our class, it’s base is still an Animal and therefore can be our zoo.

public function AddAnimal($animal)
{
    if(is_subclass_of($animal, "Animal"))
    {
        $_animals[] = $animal;
    }

    $this->_animals[get_class($animal)] = $animal;
}

Now, we can create as many different kinds of animals as we want for our zoo and inherit their basic characteristics from our Animal class.   Now we know that no matter how unique, advanced, or basic our animals are, they will always have the characteristics required by our program to work, completely removing any possibility of run time error.  This entire concept is called Inheritance.

Conclusion:

With what you have learned in this article you should be able to begin building and designing basic applications using OOP techniques.   Once you are comfortable with these concepts I would encourage you to check back and read my post on Abstract and Static classes, and Polymorphism.    With those techniques you will be able to take what you learned here and bring it to a whole new dimension.

Final Code:

class Zoo
{
    private $_animals = Array();

    public function Animals()
    {
        return $this->_animals;
    }

    public function AddAnimal($animal)
    {
        if(is_subclass_of($animal, "Animal"))
        {
            throw new Exception("$animal is not an Animal Obj.");
        }

        $this->_animals[get_class($animal)] = $animal;
    }

    public function Show()
    {
        echo "<h2>Animals in the zoo:</h2>";

        foreach ($this->_animals as $animal)
        {
            echo "<a href='?action=speak&animal=" . get_class($animal) .
                "'>" . get_class($animal) . "</a><br />" ;
        }
    }

    function __construct()
    {
        $this->_animals["Cat"] = new Cat("White");
        $this->_animals["Dog"] = new Dog("Brown");
        $this->_animals["Koala"] = new Koala("Grey");
    }
}

class Animal
{
    public $_color;

    public function Speak()
    {
        return "Well, I Say!";
    }

    function __construct($color)
    {
        $this->_color = $color;
    }
}

class Cat extends Animal
{
    function Speak()
    {
        return "Meow";
    }
}

class Dog extends Animal
{
    function Speak()
    {
        return "Woof";
    }
}

class Koala extends Animal
{
    function Speak()
    {
        return "Jolly good day sir";
    }
}

$zoo = new Zoo();

$myAnimal = new Animal("Yellow");
$zoo->AddAnimal($myAnimal);

if (isSet($_REQUEST['action']))
{
    $animals = $zoo->Animals();
    $animal = $animals[$_REQUEST['animal']];

    echo "The " . $animal->_color . " " . get_class($animal) .
       " said '" . $animal->Speak() . "'";
}

$zoo->Show();

— Live, Learn, Share —

Helpful Books: