Class Design in PHP


Target Audience:

Beginners to OOP programming in PHP.  Anyone looking for a general explanation of how to use classes in PHP.

Related Material:

PHP Manual – Class

OOP in PHP

Coding Standards and Religion Wars

Introduction:

Classes are the core of OOP design.  The whole idea behind OOP is to group similar functionality together in objects.  These objects represent real life things such as people, places or things.  In some ways, if a program was a sentence, all the nouns in that sentence would be objects.

EX: Cat in the Hat.

In this example we would have two objects, Cat and Hat.  In order to build our representation of these objects we use the Class keyword in PHP.   (for more on oop design, read ‘OOP in PHP ‘ listed above)

class Cat { }

class Hat { }

These classes are used to describe our objects. The word following the class keyword describes what kind of object the class represents. Our classes represent a Cat and a Hat. To create our objects we use the following syntax.

$myCat = new Cat();

Look at the new keyword. This tells PHP we want to make a new object of type Cat. The parenthesis are required and invoke the classes constructor. The constructor is the code that is ran when the class creates a new object. We will go over the constructor more later in this article.

Technically this code has created a legit object of type Cat. Our Cat class however is very basic and contains no real useful information or actions. In order to better describe our Cat we need to give it some Properties. Properties describe the object like an adjective would describe a noun.

EX: The green calico cat sat on the tall striped hat.

Above the adjectives ‘green’ and ‘calico’ describe the cat while ‘tall’ and ‘striped’ describe the hat. To save this descriptive information we need to declare some class fields. (Fields are sometimes called ‘members’ and are treated the same way).

class Cat
{
    var $_color;
    var $_breed;
}

NOTE: Good practice has us name our fields using the _ prefix. This lets us know quickly that his var represents a field for this class. You may also see some people use the m_ and f_ prefixes to represent ‘members’ or ‘fields’.

Ok so now we have some fields to store the information describing our cat. Next we need to protect those fields by limiting how they can be accessed. These fields are like our DNA and very important so it’s always a good idea to control how they can be accessed.

To this we are going to use the ‘public’,’private’, and ‘protected’ keywords. All fields are public by default, which means they can be accessed within or from outside the object. This can be very bad because it allows your fields to be changed by anyone. This tends to cause unexpected run-time errors.

Protected means the fields can only be accessed by functions inside the class or by classes that extend the class. Since this lesson does not get into inheritance and extending classes we will not be using this option.

Private is the most secure of all the options This means the fields can only be accessed by functions within the class. This is good because then you can control when and how that information can be changed or accessed. Normally this is the best option to choose for class fields and we will be using it for our cat.

class Cat
{
    private $_color;
    private $_breed;
}

Now we need a way to set those fields with the information we want. Because we set them as private we can’t set them from outside our obj. Meaning the following code would result in an exception.

$myCat = new Cat();
$myCat->_color = "green";

So how do we set the values of these fields? In our case our cats color is ‘green’ and breed is ‘calico’. To do this we are going to use our classes constructor. As described above the class constructor is a block of code that is executed when the class is instantiated, or created using the new keyword.

By default the constructor is called to create a representation of the object. This code is part of the php language and ran every time a class is instantiated. Instantiated means an instance of that class is being created in the form of an object. We can add special instructions to that code using our own __construct method that is ran after the default constructor.

class Cat
{
    private $_color;
    private $_breed;

    function __construct()
    {
        $this->_color = "Green";
        $this->_breed = "Calico";
    }
}

Looking at the code above you should be able to tell what is going on here. The only thing that might be different is the $this keyword. This special variable is a reference to the objects fields. So in essence we are setting ‘this’ cat’s color and ‘this’ cat’s breed. Now each time the constructor is ran the cat’s fields will be set to describe the cat.

OK Great you say, but what if I don’t want to have just green calico cats. What I want to have a lot of different kids of cats. The answer to that is easy. Just like with any other function the __construct function can be passed in values as parameters. To allow the creator of the object a way to describe the Cat themselves we will pass in a variable for both color and breed. Then we will use those values to set the cat’s fields.

class Cat
{
    private $_color;
    private $_breed;

    function __construct($color, $breed)
    {
        $this->_color = $color;
        $this->_breed = $breed;
    }
}
$myCat = new Cat("Green","Calico");

So now that we have a way to set the cat’s descriptive fields we might want a way to retrieve them so other parts of our program can use information about our cat. To do this we use public function inside our class to return the requested values. Their are a lot of techniques for doing this and I would encourage you to study them all. The technique I use best simulates how Properties work in c#, a strongly typed language.

First we simply need to declare a function for each field we want access to. The name of the function should describe the field it accesses.

public function Color()
{
    return $this->_color;
}

public function Breed()
{
    return $this->_breed;
}

Now when these methods are invoked by our objects they will return the values stored in our safely secured private fields. Now we can share our cat’s description with the rest of the world.

$myCat = new Cat("green","calico");
echo "The " . $myCat->Color() . " " . $myCat->Breed() . " cat sat on
    the tall striped hat.";

Output: The green calico cat sat on the tall striped hat.

So now we can create a fairly descriptive cat and can share those descriptive details with others. But what if we want to change the description of our cat? We can use our same properties to allow the user to change these values. The code to do this is below; I will explain what is going on following the example.

public function Color($value = "")
{
    if ($value == "")
    {
        return $this->_color;
    }

    $this->_color = $value;
}

public function Breed($value = "")
{
    if ($value == "")
    {
        return $this->_breed;
    }    

     $this->_breed = $value;
}

Look at the part of the code we changed starting with the function name. We added an attribute ‘$value‘ with a default value of  “” to the property function’s deceleration. This means that when the function is invoked with no attributes passed the value will default to an empty string.

Next look at the if block we added. Previously we were returning the value of our field whenever this property function was invoked. But now we only want to return the property value if another value is not passed into the property. The if statement checks the value of our $value variable to see if it is an empty string. If it is empty, it returns the current value of our private field.

If the value passed in is not empty then we know we need to set the field to the new passed in value. This is done the same way we do it in our constructor, using the $this-> keyword. Now if we want to change our cat’s descriptive properties we have a way to do so outside the class.

$myCat = new Cat("green","calico");

echo "The " . $myCat->Color() . " " . $myCat->Breed() . " cat sat on
    the tall striped hat.";

Output: The green calico cat sat on the tall striped hat.
$myCat = new Cat("purple","calico");

echo "The " . $myCat->Color() . " " . $myCat->Breed() . " cat sat on
   the tall striped hat.";

Output: The purple calico cat sat on the tall striped hat.

Now see if you can take what you have learned at complete our Hat class as described in our sentence. Try and do this on your own before looking at our code below. To get you started I will give you the names to use for your Hat’s fields.

$_pattern, $_size

Complete code so far:

class Cat
{
    private $_color;
    private $_breed;

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

    public function Color($value = "")
    {
        if ($value == "")
        {
            return $this->_color;
        }

        $this->_color = $value;
    }

    public function Breed($value = "")
    {
        if ($value == "")
        {
            return $this->_breed;
        }    

        $this->_breed = $value;
    }
}

class Hat
{
    private $_pattern;
    private $_size;

    function __construct($pattern, $size)
    {
        $this->_pattern = $pattern;
        $this->_size = $size;
    }

    public function Pattern($value = "")
    {
        if ($value == "")
        {
            return $this->_pattern;
        }

        $this->_pattern = $value;
    }

    public function Size($value = "")
    {
        if ($value == "")
        {
            return $this->_size;
        }    

        $this->_size = $value;
    }
}

Now that we have our Cat and Hat objects and get at their descriptive properties we can use them in our program to complete out sentence.

$myCat = new Cat("green","calico");
$myHat = new Hat("striped","Tall");

echo "The " . $myCat->Color() . " " . $myCat->Breed() . " cat sat on the "
    . $myHat->Size() . " " . $myHat->Pattern() . " hat.";

Output: The green calico cat sat on the tall striped hat.

So that is great you say. But why spend so much work doing something that we could already do for the most part just using an associative array? Obviously their are benefits to using classes or else they would not be an option. To learn more about how to use classes and objects in an OOP application please read our article on OOP in PHP.

One of the strengths of classes is their ability to perform actions as well as hold descriptive information. The actions they perform are just like verbs in a sentence.

EX: The green calico cat sat on the tall striped hat.

Our cat needs the ability to sit before it can sit in our hat. To do this we will create a function within our class to perform the action.

public function SitOn() {  }

Next we are going to need a another field to let us know what the cat is sitting on. It’s good practice to keep all our fields together at the beginning of the object so they can easily be located later. Going back up to the top of our cat class we are going to add a new field called $_seat.

class Cat
{
    private $_color;
    private $_breed;
    private $_seat;    // Obj

    ...
}

Note: the in the code example below simply indicates the rest of the code we have dealt with in this article would follow as normal.

Another good practice is to comment the fields that store references to other objects so that you and others understand the intention of that field without having to scan all the code. Now that we have a SitOn() function and a place to store what we are sitting on we can complete our function. First we will add an attribute to our function so we can pass in what we are sitting on.

public function SitOn($seat)
{
    $this->_seat = $seat;
}

The above function should be self explanatory. When invoked a ‘seat’ will be passed in and the $_seat field will be set to reference that seat. This function will work just how it is but it has a small problem. Right now we are able to set the $_seat field to a value that is not an object. Our comment indicates that this field is intended to hold a reference to an object and not just a string value. As indicated previously when we talked about Property functions, we can control how our field is set. To do this we just need to add a little extra code to our function.

public function SitOn($seat)
{
    if (!is_object($seat))
    {
        throw new Exception("Seat is not an object in function SitOn.");
    }

    $this->_seat = $seat;
}

Now if the user of our object class tries to make the cat sit on something that is not an object, an exception will be thrown letting our user know they can’t do that. The last thing we need to do is provide a way for the application to find out more about what our cat is sitting on. To do this we need to create a property function for our seat. Since we only want users to be able to set this value by having the cat SitOn() a seat we don’t want our property to allow the user to set it’s value.

public function Seat()
{
    return $this->_seat;
}

Combining it all together our final Cat class should look like this.

class Cat
{
    private $_color;
    private $_breed;
    private $_seat; // Obj

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

    public function Color($value = "")
    {
        if ($value == "")
        {
            return $this->_color;
        }

        $this->_color = $value;
    }

    public function Breed($value = "")
    {
        if ($value == "")
        {
            return $this->_breed;
        }    

        $this->_breed = $value;
    }

    public function Seat()
    {
        return $this->_seat;
    }

    public function SitOn($seat)
    {
        if (!is_object($seat))
        {
            throw new Exception("Seat is not an object in function SitOn.");
        }

        $this->_seat = $seat;
    }
}

Now our cat has a way to sit on an object and to let others know things about the object it is sitting on. Going back to our original sentence we can now replace all the nouns, adjectives, and verbs with information about our objects.

$myCat = new Cat("green","calico");
$myHat = new Hat("striped","Tall");

$myCat->SitOn($myHat);

$mySeat = $myCat->Seat();

echo "The " . $myCat->Color() . " " . $myCat->Breed() . get_class($myCat) . 
     " sat on the" . $mySeat->Size() . " " . $mySeat->Pattern() .
     " " . get_class($mySeat) . ".";

Output: The green calico cat sat on the tall striped hat.

The get_class() function is a built in function in PHP that returns the Class name responsible for creating an object. In our case our $myCat object was created by the Cat class, and the $mySeat object was created originally by the Hat class.

Although this is an unlikely application, the purpose was to show you how to create your own class objects.  For more practical examples of classes, objects and how to use those objects please see my posts on OOP in PHP.

Final Code:

class Cat
{
    private $_color;
    private $_breed;
    private $_seat; // Obj

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

    public function Color($value = "")
    {
        if ($value == "")
        {
            return $this->_color;
        }

        $this->_color = $value;
    }

    public function Breed($value = "")
    {
        if ($value == "")
        {
            return $this->_breed;
        }    

        $this->_breed = $value;
    }

    public function Seat()
    {
        return $this->_seat;
    }

    public function SitOn($seat)
    {
        if (!is_object($seat))
        {
            throw new Exception("Seat is not an object in function SitOn.");
        }

        $this->_seat = $seat;
    }
}

class Hat()
{
    private $_pattern;
    private $_size;

    function __construct($pattern, $size)
    {
        $this->_pattern = $pattern;
        $this->_size = $size;
    }

     public function Pattern($value = "")
     {
         if ($value == "")
         {
             return $this->_pattern;
         }

         $this->_pattern= $value;
     }

     public function Size($value = "")
     {
         if ($value == "")
         {
             return $this->_size;
         }    

          $this->_size= $value;
     }
}

$myCat = new Cat("green","calico");
$myHat = new Hat("striped","Tall");

$myCat->SitOn($myHat);

$mySeat = $myCat->Seat();

echo "The " . $myCat->Color() . " " . $myCat->Breed() . " " . get_class($myCat)
      . " sat on the " . $mySeat->Size() . " " . $mySeat->Pattern() . " "
      . get_class($mySeat) . ".";

Output: The green calico cat sat on the tall striped hat.

— Live, Learn, Share —

Helpful Books:

11 thoughts on “Class Design in PHP

  1. This is a good approach to OO design. However, you should fix the __constructor() method in __construct(). Also you might consider a coding standard are usually methods start with a lowercase letter and it will give a much more serious look to your code.

    1. Thanks for the read Piccolo. This goes to show that it is not a good idea to post a article late at night without editing it. You are absolutely right, __construct is appropriate method not __constructor. Thanks for the heads up. As far as standards go, the important thing is that everyone in your organization or team is using the same standard whatever that be. The standard you are referring to is PHP’s standard, which uses camel case for function names. Most other languages use Pascal case for functions, which is what I choose to use, mainly so that people familiar with C based languages, and now C# and .NET, can easily adapt. I would love to hear your thoughts on the differences in these naming conventions and why you prefer one over the other.

      1. Good Write up Piccolo. I am linking to your post in the ‘Related Material’ section of this post. Nice work.

    1. Hey Max, Thanks for the read! __construct() was introduced as a replacement to naming your constructor the same as your function name as of PHP 5. Personally I prefer the old method as you describe but it is depreciated and will likely go away with the next version of PHP.

  2. If you are going to provide Breed() and Color() methods for private variables that do no more than provide public access to the variable, you might as well just make the variables public instead.

    1. That is a question I hear a lot… It has a simple answer. The concept is called encapsulation, which is where you limit access to your fields though public properties, or in PHP public functions that represent a property. Seems pointless when you realize you are just adding a layer between the object and it’s private methods, however in large projects it reduces run time errors and headaches. How you might ask? My example above simply sets the value to the value passed in… but what if I don’t want the user to be able to pass in any value? I can add code to my Breed() function to throw an exception if the user tries to set it to a value or type that would cause problems in my class. You should consider reading up more on encapsulation. I will be adding a post on encapsulation as part of my serious of articles to. Thanks for the read!

Leave a comment