Encapsulation in PHP


Target Audience:

Beginners to Object Oriented Programing who use PHP.  Anyone looking for a detailed explanation of what encapsulation is and examples of how it’s used.

Languages Used:

PHP 5+

Related Material:

PHP Manual – Class
PHP Good Practices 1 – Naming Conventions
PHP Good Practices 2 – Self-Documenting Code
Class Design in PHP
OOP in PHP

Introduction:

encapsulation
2. The ability to provide users with a well-defined interface to a set of functions in a way which hides their internal workings. In object-oriented programming, the technique of keeping together data structures and the methods (procedures) which act on them.
(1998-09-07)

Taken from dictionary.comComputing Dictionary.

In order to understand the purpose of encapsulation you first need to  understand the purpose of classes.   Classes are the blueprints for objects, but more then that they are like the building blocks and tools used to make your application.  Your classes should be designed to represent specific characteristics and functionality.  In order for them to be used properly as they were designed, you will need to limit how users of the class can interact with those characteristics and functionality.

When I speak of ‘users of the class’ I am talking about anyone who uses the class within their application, including you.  After all these ‘tools’ and ‘materials’ were designed to help you build an application, and that is how they should be thought of when you design them.

Encapsulation is the process of creating that interface for users of your class to use.  This is done through the use of visibility modifiers, and interface functions that strictly define how a user can interact with your class.  By doing this you ensure your class is being used as you intend for it, and limit the possibilities of miss-use and unexpected run-time errors.

Below we will go over the process of encapsulating a class and explain in detail the purpose of each step with examples of use.

Visibility Modifiers

In PHP there are three visibility modifiers; private, protected, and public.  These modifiers are used to define what level of visibility a variable or function within your class has.  Each of the modifier keywords represent a level at which the variable or function can be seen outside and within the class.

When we talk about ‘seen outside’ the class, I am referring to the interaction with an object that was instantiated from your class.   If your class represents a dog and I create a new dog object from your class, I can then interact with the dog characteristics that are visible outside of the class.

If you think of it just like in the real world, if you have a dog in front of you, you can interact with that dog.  You can clearly see the dogs visible characteristics such as size, color, and probably even breed.  You can also perform actions with the dog such as petting it, giving it a command, playing fetch, etc.   Other characteristics and activity is not so visible however such as the dogs temperament or health, or the actions that keep the dogs heart beating and lungs working.   They are very important to the makeup of the dog, however your interaction with the dog is limited only to what is visible to you.

Public keyword modifier is used to define a variable or function as being visible to everyone, everywhere.  When this modifier is used the variable or function following is visible to the users using your class as well as all the inner workings of your class.  This modifier is the only modifier that allows interaction outside of the class.

Private keyword modifier is used to define a variable or function as being visible only to the inside of the class.  When this modifier is used the variable or function following is invisible to the users using your class, but all the code that you write inside your class will be able to see it.

Protected keyword modifier is similar to the Private keyword modifier in that it is visible inside of the class but not to users outside the class.  In addition to that however, the protected keyword also allows child classes that extend the class to see the characteristics as well.  This is useful when inheriting characteristics from a more generic class.  See Inheritance.

Interface Functions

An interface function is nothing more then a public function inside your class that interfaces with a private or protected member of the class.  This is where encapsulation comes in.   When you want users of your class objects to interact with the internal workings of your class, you do so by providing them an interface function that has public visibility.

These interface functions can be used to either return data about the class to the user in a controlled fashion, or to allow the user to change or add data to the class object.  This is done to give you, the author of the class, control over what can be changed, how it can be changed, and even when it can be changed.

So what is the benefit?  Stable Code!  If you have a class variable that is an integer , and you have a function in your class that uses that integer to calculate a value, that function will break if the value is anything but an integer.   If you create your interface function so that it checks the users input and makes sure it is an integer before setting the private data field, you know your calculation function will work when called.

Lets Apply It!

To apply this concept we are going to create a quick and simple person class.  This class will contain a very basic data structure.  We need a variable to hold this person’s name and age.  We will need to supply a constructor so that we can assign the person a name and optional age when we create the object.  We will also need to be able to change the person’s age from outside the class.  Finally we will need to create a public function that will tell us how many years the person has until retirement.

Step 1. Build Class Structure.   Our first step is to simply define the structure of our class.  This includes defining our private data fields or members.

class Person
{
    private $_name;
    private $_age;
}

Step 2. Build Class Constructor.  We need a way to assign a name to our person and an optional age when we create our object.  To do this we must have a class constructor.

class Person
{
    private $_name;
    private $_age;

    function __construct($name, $age = 0)
    {
        if (!is_int($age))
        {
            throw new Exception("Cannot assign non integer value to integer field, 'Age'");
        }

        $this->_age = $age;
        $this->_name = $name;
    }
}

Explanation: Our constructor function takes two parameters, $name and $age, where age is a default parameter, meaning if the user does not specify an $age, it will use the default value of 0.  The if statement at the beginning of the constructor checks to make sure age is an integer before setting it.  If it is NOT an integer, which would create problems, we are throwing an error, forcing our users to use the class the way we intend for them to use it.

Step 3. Encapsulate $_age, giving the  user a way to change or set the person’s age through a interface function.   This is done simply be creating a public function the user can call.

     public function setAge($age )
    {
        if (!is_int($age))
        {
            throw new Exception("Cannot assign non integer value to integer field, 'Age'");
        }

        $this->_age = $age;
    }

Explanation: The setAge() function only requires a single parameter, $age. We know age must be an integer so we check the user’s input to make sure it is a integer first.  If it isn’t we throw an error, forcing the user to use our interface function the way we intend it be used.  If the condition passes then our private age variable is set to the value of the user’s input $age.

Step 4. Provide an interface to retirement years.  To do this we will create another public function for our user to interface with.  This function will use the person’s age to figure out how many years they have left to retire.

    public function yearsToRetire()
    {
        return 67 - $this->_age;
    }

Explanation: This function does not require any parameters.  Amusing retirement age will be 67, simply return the result of 67 – the person’s age.  Since we know that age is always going to be an integer, we can safely execute this function any time!

Put It All Together!

class Person
{
    private $_name;
    private $_age;

    function __construct($name, $age = 0)
    {
        if (!is_int($age))
        {
            throw new Exception("Cannot assign non integer value to integer field, 'Age'");
        }

        $this->_age = $age;
        $this->_name = $name;
    }

   public function setAge($age)
    {
        if (!is_int($age))
        {
            throw new Exception("Cannot assign non integer value to integer field, 'Age'");
        }

        $this->_age = $age;
    }

   public function yearsToRetire()
    {
        return 67 - $this->_age;
    }
}

$person = new Person("Wes");
$person->setAge(31);

echo $person->yearsToRetire();

Take It Further.

So now you have a Person class with an encapsulated $age filed and a interface function that allows you to find out when the person retires.  The problem is, retirement age is not set.  If the age ever changes we need a way for the user to change it.   See if you can change our yearsToRetire function so that the user can pass the retirement age into the function.  Something to consider; check your users input and make sure you are working with integers.

– Live, Learn, Share –


Helpful Books:

About these ads

18 responses to “Encapsulation in PHP

  1. Pingback: Webby Scripts Encapsulation in PHP « Shell Scripts·

    • “The term encapsulation is often used interchangeably with information hiding. Not all agree on the distinctions between the two though; one may think of information hiding as being the principle and encapsulation being the technique. A software module hides information by encapsulating the information into a module or other construct which presents an interface” — From Wikipedia

      Jonathan, this is a good debate to bring up. Your thought is obviously that encapsulation and information hiding are two specifically different things. My thought is more in line with the above, that information hiding is a principle and encapsulation is the technique of applying that prinicple. After all, encapsulation without information hiding would not server much of a purpose would it?

    • “It would be nice if you discussed encapsulation separate from OOP as well.”

      “In this sense, the idea of encapsulation is more general than how it is applied in OOP: for example, a relational database is encapsulated in the sense that its only public interface is a Query language (SQL for example), which hides all the internal machinery and data structures of the database management system. As such, encapsulation is a core principle of good software architecture, at every level of granularity.”

      Yes, the term encapsulation is broader then OOP, I agree. I should have maybe been more specific in my title but I think most people get the point. Encapsulation can best be defined as…

      “the process of compartmentalizing the elements of an abstraction that constitute its structure and behavior; encapsulation serves to separate the contractual interface of an abstraction and its implementation.”

      By this definition, encapsulation does not even only apply to computer programming.

  2. These kinds of heavyweight object-oriented techniques are really questionable for PHP apps. Unlike server or desktop applications that run for a long time, PHP apps almost always survive only long enough to handle a single HTTP request. Erecting elaborate OOP scaffolding for that is not always a great idea.

    A simple array would encapsulate your Person (although it wouldn’t hide anything).

    As I’ve gone into on my own blog, I think code examples posted online should be rigorously correct and show good technique, because less-experienced programmers often copy/paste code they find on the web.

    You should probably use is_numeric($age) and intval($age) instead of is_int, so a client of your class can pass a string containing a valid integer; that kind of result often comes from database queries or reading values from an XML file, for example.

    Zero is not a great value for unknown age; it would probably be better to use null (also consistent with relational databases).

    Your constructor and setAge functions rigorously check for an integer but don’t check that the age is positive, or less than some reasonable maximum like 120. PHP will likely detect and throw an error itself when a non-integer is used in a calculation, but it won’t detect an age of 1024 as an error.

    yearsToRetire() will return a negative value if the person is older than 67.

    Overall this is a pretty bad example of encapsulation and OOP.

    • “Unlike server or desktop applications that run for a long time, PHP apps almost always survive only long enough to handle a single HTTP request.”

      – Correct, do to the nature of web applications and the HTTP protocol when you make a web request, that request lasts in memory long enough to execute and then it dies. Using OOP for structure and data in this kind of environment would be different then a server or desktop application. However, objects can be saved in sessions, or other techniques can be used to retain that structure and data from one request to another, providing the same benefits of OOP for web.

      “You should probably use is_numeric($age) and intval($age) instead of is_int”

      – Yes you could, and you should if that is how you want to implement your class. However this does not relate to the topic. You can implement your interface however YOU want to. And that is the point.

      “Zero is not a great value for unknown age; it would probably be better to use null (also consistent with relational databases).”

      – NULL is not an integer value and my field is intended to hold an integer value. Yes PHP is loosely typed, but that does not mean I have to code loosely.

      “Your constructor and setAge functions rigorously check for an integer but don’t check that the age is positive, or less than some reasonable maximum like 120.”

      – Good points, and more then likely other checks would be considered as well. Again, this depends on the need for the class and your intention for use. Your suggestions here would indeed further stabilize our data.

      “PHP will likely detect and throw an error itself when a non-integer is used in a calculation, but it won’t detect an age of 1024 as an error.”

      – Going back to the part about avoiding unwanted runtime errors. Does it make more sense to rely on the language to clean up after you, or should you clean up after yourself? Another debate? Yes, setting a cap on age is something that could be done, but should it be? Lets say we say the users types in 130 for an age, is that considered valid? Or 150? Where i that magic number. The question becomes, at what point do you leave it up to the implementer of the class to be responsible for their implementation? One thing I can see for sure, is we should be returning 0 if the age is equal to or higher then the retirement age, because then they would already be retired.

      Thanks for the read and your feedback!

  3. “However, objects can be saved in sessions, or other techniques can be used to retain that structure and data from one request to another, providing the same benefits of OOP for web.”

    Some PHP objects can be safely serialized and stored in a session, but not all. For example objects that contain resources (like an open database connection or file handle) can’t be serialized. PHP requires the class definition (and any superclasses) to be defined before an object can be unserialized, so my point about erecting elaborate OOP scaffolding for trivial objects is still relevant.

    http://www.php.net/manual/en/language.oop5.serialization.php

    So instead of defining a class and instantiating it, a serialized object saved in a session requires defining the class and unserializing it. That’s a lot of work when this would work:

    $person = array(‘name’ => ‘Tom Jones’, ‘age’ => 43);

    I’m not against OOP in PHP (use it all the time) but you need to think about the tradeoffs and costs of OOP in an environment where the code is compiled, executed, and discarded for each HTTP request.

    • But that is the case for MOST web applications, is it not? Storing data in an array is easier sure.. but I can set your age to anything I want now… This completely defeats the purpose of why I encapsulated the age.

      “Some PHP objects can be safely serialized and stored in a session, but not all. For example objects that contain resources (like an open database connection or file handle) can’t be serialized”

      – Nor would these kinds of resources be retained from request to request if you didn’t use OOP. Can you show how using an array would be any different? I understand what you are attempting to get at, but your argument seems to be lacking. Obviously you can do the same thing without OOP, but if we wanted to talk about that the article wouldn’t be named ‘Encapsulation in PHP’

  4. So, what are these costs? Performance?
    I cannot live without oop even in php where now there is a decent implementation (back in php 4 it was difficult to use at its best). Even if objects are throwed away at the end of every request, the point is in writing maintanable and testable code, not in saving cpu cycles. :)

    • Yes! That is the point… :) One last comment, is it wise to store things like open database connections or file resource handles inside of class objects anyway? This is a real question, I would like to hear people’s thoughts.

  5. Pingback: Encapsuler en PHP | traffic-internet.net·

  6. Pingback: 網站製作學習誌 » [Web] 連結分享·

  7. nice tutorial thanks very much…
    I was confused about data encapsulation and I also didn’t know much more about interface you make my sense clear. Thanks ,, good work and keep it up.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s