Introduction to PHP OOP

This is the first in a series of articles about using PHP to do objected oriented programming, or OOP. They were originally published elsewhere but are no longer available at that location, so I'm reposting them here.

Since the introduction of PHP 5 in 2004, PHP has had an object model worthy of that description and became a truly modern language for use on the web. Earlier PHP scripts would have been of the kind where, to quote from Alice's Adventures, you would "Begin at the beginning, and go on till you come to the end: then stop." Nowadays that very procedural approach is less common in PHP, so this article takes a look at some of the basic object oriented features available in the language and shows some examples of using them with code examples.

Using OOP (Object Orientated Programming) enables us to architect our systems much more clearly, and to make them more manageable and more maintainable. This technique also allows us to separate form from function to create clean, navigable codebases with plenty of opportunities to reuse code, apply design patterns and bring in concepts from other brances of computer science.

Objects vs Classes

While the terms "object" and "class" are often used almost interchangeably in the world of software, there is a definite conceptual difference between the two. A class is the blueprint or recipe; it describes what the object should be, have and do. So a class might look like this:

class Elephpant {
    public $colour;
 
    public function dance() {
        echo "elephpant dances!\n";
        return true;
    }
}

elephpant.php

An object, on the other hand, is an actual instantiation of the class - its an actual thing, with values and behaviours. In the example below, $ele is the object:

include('elephpant.php');
 
$ele = new Elephpant();

We can inspect $ele to make sure that it is, in fact, an object of the class Elephpant, using the print_r command. Adding this to our code sample as shown, we see the output below:

include('elephpant.php');
 
$ele = new Elephpant();
print_r($ele);
Elephpant Object
(
    [colour] =>
)

This output shows an object, of type Elephpant, and with a single empty property named "colour". For more information about the objects exact properties and their values, you can also use var_dump, which gives a more detailed output showing in detail the datatypes of each property. This is particularly useful for spotting empty strings, nulls and false.

Using Objects, Their Properties and Methods

Our class, Elephpant, has a property and a method (OO-speak for "function") already defined inside it, so how can we interact with these? Let's start by setting the colour property; we use the object operator which is a hyphen followed by a greater than sign.

include('elephpant.php');
 
$ele = new Elephpant();
 
// set the colour property
$ele->colour = "blue";
 
// now use that property
echo "The elephpant is " . $ele->colour;

The output of this script reads "The elephpant is blue". The property will remain set on the object until the object is destroyed, or the property overwritten or unset. Objects are a great way of keeping things together that belong together, for example information about an elephpant!

Similarly we can call the method using the same operator - the brackets after the call let PHP know its a method rather than a property, and if we had parameters to pass in they'd go between the brackets. Something like this:

include('elephpant.php');
 
$ele = new Elephpant();
 
// call the dance method
$ele->dance();

Look back at the class declaration for Elephpant and you'll see the dance method actually echoes from within it. Indeed when we run the code example here, we see "elephpant dances!" as our output. It is a very trivial example but I hope it does show how to call methods against our objects. An alternative approach (and probably a better one within an actual application) would be to create the string and use it as the return value for the function. Then the calling code can take the string and echo it, or do whatever else it needs to, in a more flexible way.

Inheritance

Now we know how to create and interact with objects, let's step things up a bit and look at how we can create objects which are similar in some ways and different in others, using inheritance. If you are accustomed to OOP from any other programming languages then this will seem very familiar to you, so here is a quick look at how this can be done in PHP. We already have our Elephpant class declared, so let's add a Penguin class as well. They will both inherit from the parent class Animal, which looks like this:

class Animal{
 
    public $type = "animal";
 
    public function dance() {
        echo $this->type . " dances!\n";
        return true;
    }
}

animal.php

The animal has a "type" property, and a dance() method. It uses the type property in the dance() method to create the output, using $this to refer to the current object. In PHP, $this is a special keyword which refers to the current object from within its own class.

Now we can create a Penguin class that inherits from this general Animal class, by using the extends keyword to denote its parent:

class Penguin extends Animal {
    public $type = "penguin";
}

penguin.php

The penguin class would inherit the type property set to "animal" if we didn't override it by setting the property again in this class. However even without declaring a dance() method, the penguin can dance!

include('animal.php');
include('penguin.php');
 
$tux = new Penguin();
 
// make tux dance
$tux->dance();

The above example gives the output "penguin dances!" - using the dance() method from the Animal class, which is available because the Penguin class extends it, and the type property set separately in the Penguin class itself.

Access Modifiers

Take a look at the previous example. The type is set in the class, but we could easily set it from our main code if we wanted to. Imagine if we put $tux->type = "giraffe" before we asked him to dance! Sometimes this is the desired behaviour, and sometimes it isn't. To allow us to control whether properties can be changed outside a class, PHP gives us access modifiers. An example of these are the "public" keywords you see in the classes shown above. To prevent the type property being edited from outside the class, we can declare the Penguin type to be private, so the class now looks like this:

class Penguin extends Animal {
    private $type = "penguin";
}

private_penguin.php

The following code listing shows us trying to set the now-private type property, and is followed by the resulting output.

include('animal.php');
include('private_penguin.php');
 
$tux = new Penguin();
 
// change the type
$tux->type = "linux penguin";
// make tux dance
$tux->dance();
Fatal error: Access level to Penguin::$type must be public (as in class Animal) in /home/lorna/.../OOP/private_penguin.php on line 5

The resulting message feeds back to the user that the type property can't be modified, and even includes the detail that the property was public in the parent class. Access modifiers are pretty powerful, we should look at them in more detail.

Access modifiers can be applied to properties and to methods and to properties. The options are public, private and protected. In PHP4, these weren't available and everything is public. As a result, and to maintain backwards compatibility, if an access modifier isn't specified then the property or method defaults to being public. This isn't recommended practice however, and it is best to be explicit about which is intended.

Public: The public access modifier means that properties and methods can be accessed from anywhere, within the scope of the object itself, and also from outside code operating on an object.

Private: The method or property is only available from within the scope of this specific class. Before using this option, read on to find out about the "protected" access modifier.

Protected: The method or property is available from within this class, and from within any classes with extend or implement this class. This is ideal where you don't want external code to change the class, but you do want to be able to extend the class later and take advantage of this property or method. Protected is more flexible than private and almost always the better choice.

Using these access modifiers we can control where our class methods and properties can be accessed from. We looked at an example of properties and this works in the same way for method calls - they cannot be accessed from outside of the class definition unless they are declared to be public. It can be very useful indeed to declare methods as protected, where they are internal helper methods used by other class methods but not intended to be accessed directly. In PHP4 there was no support for this and so the internal methods were sometimes named with an underscore to hint that this was their intended use - it is still possible to see this naming convention in use today, although it is not needed.

Using OOP in PHP: Practical Example

Object Oriented design is particularly useful where you have data objects that relate to one another - so it is very common for example to have OOP used to deal with data. PHP 5 has the PDO (PHP Data Object) classes which are a great way to talk to a backend database, either mysql or any other kind of database, and using the object oriented interface offered by this extension ties in well with the usage I have shown here.

A common mistake for those coming to OO for the first time is to declare methods inside a class but then instantiate a single copy of that and pass in data such as the ID of the data to each method. Here's an example of a user class that does this:

class User {
    /**
     * getDisplayName 
     * 
     * @param int $user_id the user_id of the user in the database table
     * @access public
     * @return string Display name of this user
     */
    public function getDisplayName($user_id) {
        $sql = 'select display_name from users where user_id = '.$user_id;
        $results = mysql_query($sql);
        $row = mysql_fetch_array($results);
        return $row['display_name'];
    }
 
    /**
     * getFriends 
     * 
     * @param int $user_id the user_id of the user in the database table
     * @access public
     * @return array An array of friend_ids
     */
    public function getFriends($user_id) {
        $sql = 'select friend_id from user_friends where user_id = '.$user_id;
        $results = mysql_query($sql);
        $friends = array();
        while($row = mysql_fetch_array($results)) {
            $friends[] = $row['friend_id'];
        }
        return $friends;
    }
}

user.php

And some code that uses it:

include('user.php');
mysql_connect('localhost','root','');
mysql_select_db('test');
 
$user = new User();
echo "User known as: " . $user->getDisplayName(1) . "\n";
 
 
$friends = $user->getFriends(1);
echo "Friends with: " . implode(', ',$friends) . "\n";

If you want to run this code yourself, then you can set up the database tables using this script:

 
CREATE TABLE `user_friends` (
  `user_friend_id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `friend_id` int(11) NOT NULL,
  PRIMARY KEY (`user_friend_id`)
) 
INSERT INTO `user_friends` VALUES (1,1,3),(2,1,5);
 
CREATE TABLE `users` (
  `user_id` int(11) NOT NULL AUTO_INCREMENT,
  `first_name` varchar(20) DEFAULT NULL,
  `last_name` varchar(50) DEFAULT NULL,
  `display_name` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`user_id`)
) 
INSERT INTO `users` VALUES (1,'Lorna','Mitchell','lornajane');

user.sql

This is more like a function library than an actual object, and although it works perfectly well and does have its applications, it can be better to aim to take advantage of more object oriented features. To do this, a new object should be created for each item the system handles, and if it has an ID and perhaps some other properties, these should be set as part of the object. Then rather than creating a single user object and doing getFriends(42) on it, you'd have a user with ID 42 which did $user->getFriends().

Here's a follow up example with a class and how to use it, this will give better performance and enable you to clearly see which data goes with which object where there are multiple items on a page:

class User {
    /**
     * getUserById 
     * 
     * @param int $user_id the id of the user row in the table
     * @access public
     * @return true if the user was found
     */
    public function getUserById($user_id) {
        $sql = 'select first_name, last_name, display_name from users where user_id = ' . $user_id;
        $results = mysql_query($sql);
        $row = mysql_fetch_array($results);
        $this->user_id = $user_id;
        $this->first_name = $row['first_name'];
        $this->last_name = $row['last_name'];
        $this->display_name = $row['display_name'];
 
        // in real life, there would be escaping and error handling and we'd only return true if we got data
        return true;
    }
 
    /**
     * getDisplayName 
     * 
     * @access public
     * @return string Display name of this user
     */
    public function getDisplayName() {
        return $this->display_name;
    }
 
    /**
     * getFriends 
     * 
     * @access public
     * @return array An array of friend_ids
     */
    public function getFriends() {
        $sql = 'select friend_id from user_friends where user_id = '.$this->user_id;
        $results = mysql_query($sql);
        $friends = array();
        while($row = mysql_fetch_array($results)) {
            $friends[] = $row['friend_id'];
        }
        return $friends;
    }
}

user2.php

include('user2.php');
mysql_connect('localhost','root','');
mysql_select_db('test');
 
$user = new User();
// populate the object
$user->getUserById(1);
echo "User known as: " . $user->getDisplayName() . "\n";
 
$friends = $user->getFriends();
echo "Friends with: " . implode(', ',$friends) . "\n";

In Summary

This has been a very introductory look at some of the object oriented features available in PHP, to get you started out with the basics of working with OO code and also writing your own. If this has helped you take your first OOP steps, then let us know by leaving a comment and let us know what you built!

Edit: The next article in the series is now online http://www.lornajane.net/posts/2012/a-little-more-oop-in-php

22 thoughts on “Introduction to PHP OOP

  1. Sorry to bark in with harsh criticism, but I have several points to object:

    1. The SQL code is vulnerable to SQL Injection
    2. having a user object doing SQL violates the SOLID principle.
    3. having the find method "populate" the same user method over and over again is not really good OOP and leads to very hard to maintain code.

    From your recent comment I see that this blog post is already older and just republished here. Personally I think showing this kind of code as good OOP is dangerous rather than helpful.

    • If you think this is a bad example, write a response post on your own blog explaining how to secure the tutorial code given here.

      Bashing an author without contributing something of value is just sad.

      • I'm sorry, but where exactly is this code vulnerable to SQL-injection?
        Do you guys mean this line:

        $sql = 'select friend_id from user_friends where user_id = '.$user_id;

        Don't you sanitize your input?
        Or am i missing something?

  2. Oh, please, beberlei! This is a simple introduction, stripped down to help the interested beginner. This is the way a good instructor works -> you start at the beginning. Look at the things you mentioned (SQL injection, SOLID principle). Is she suppose to cover everything simply to get across a few pointers for beginners in this area?

    • The problem with this beginning is that we are trying to teach OO in a procedural way, as if fields, methods and inheritance were its foundations; but the real foundations are classes, responsibilities and collaborations.

  3. It's true but why give bad(I agree with Benjamin) examples and don't explain it. This is a blog post - not a part of a book. Many people may follow it, because they are unaware of the vulnerabilities in the code and would consider that a more experienced person than themselves has written the code. If I were you and did not have the time to rework the examples, I would have waited until I did. I'm not trying to offend the author! I'm actually quite often reading this blog :)

  4. I've been working with PHP for about 8 years now and if there's one thing i hate are the so called experts/gurus. It seems too common nowadays that when a article about PHP gets posted there are people in line ready to smash it. You guys take the fun out of writing code. @beberlei you could have kept that shhh to yourself. I'm sure @lornajane is all aware of SQL injections and honestly I'm glad she left it out this post was already long enough.
    If you're new to OOP or even PHP I say have fun and enjoy building stuff. You can read a 100 books and 100 blog posts and there will always be someone smashing what's written, as if they invented the language.
    @derickrethans I'm a big fan sorry I missed you @atlantaPHP
    And @lornajane thanks for taking the time to contribute

  5. Pingback: Lorna Mitchell: A Little More OOP in PHP : Atom Wire

  6. I really appreciated the article and in particular the perspective of manipulating an object rather than just using classes as a means to create a library of associated functions which seem to appear so often in examples.
    I had to comment though because I found the misspelling of Elephant quite jarring and distracting - sorry if this seems picky.

  7. Great tutorial Lorna. I understood very well how OOP works and I`m looking forward to read the next chapter. Thank You!

  8. Even though tutorial is using some old methodology like mysql instead of msqli or pdo but still its a great help for a beginner and i found it very clear ............thanks a lot and i m surely going to see another link provided in bottom ...thanks once again your effort is highly appreciated.

  9. As someone who is swapping over too oop from procedural I find these tutorials really helpful. As for the negative comments regarding SQL and SQL injections etc. my real aim at present is to adopt the oop format. This tutorial does well to explain the basics. If these examples were to cover 'all' the intricacies of the PHP language at this level, the code (and descriptions) would become overbloated and possibly useless for a newbie to follow logically. I think at this level anyone who finds this code useful is highly unlikely to be writing realworld critical apps from this point. Perhaps a foot note about omissions and vulnerabilities may not go a miss with links to relevant tutorials. But personally I can't criticize this helpful tutorial. Thanks Lorna :)

  10. hey Lorna M. I think you rock! Please any updates for the newbies in OO? You know there are some peolple like me who look up to people like you because you are just wonderful, helping people out.
    I will be wiating right here! Thanks again!

  11. I was looking for articles which can help me out with examples for how to start with OOPS. And i found this article very useful as it is very well documented & step by step explanation with examples helped me a lot. Thanks a lot for posting this!!!

Leave a Reply

Please use [code] and [/code] around any source code you wish to share.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>