Object-Oriented PHP for Beginners

Object-Oriented PHP for Beginners

Tutorial Details
  • Program: PHP
  • Version (if applicable): PHP 5+
  • Difficulty: Intermediate
  • Estimated Completion Time: 2 Hours

Twice a month, we revisit some of our readers’ favorite posts from through out the history of Nettuts+. This tutorial was first published in July, 2010.

For many PHP programmers, object-oriented programming is a frightening concept, full of complicated syntax and other roadblocks. As detailed in my book, Pro PHP and jQuery, you’ll learn the concepts behind object-oriented programming (OOP), a style of coding in which related actions are grouped into classes to aid in creating more-compact, effective code.


Understanding Object-Oriented Programming

Object-oriented programming is a style of coding that allows developers to group similar tasks into classes. This helps keep code following the tenet “don’t repeat yourself” (DRY) and easy-to-maintain.

“Object-oriented programming is a style of coding that allows developers to group similar tasks into classes.”

One of the major benefits of DRY programming is that, if a piece of information changes in your program, usually only one change is required to update the code. One of the biggest nightmares for developers is maintaining code where data is declared over and over again, meaning any changes to the program become an infinitely more frustrating game of Where’s Waldo? as they hunt for duplicated data and functionality.

OOP is intimidating to a lot of developers because it introduces new syntax and, at a glance, appears to be far more complex than simple procedural, or inline, code. However, upon closer inspection, OOP is actually a very straightforward and ultimately simpler approach to programming.


Understanding Objects and Classes

Before you can get too deep into the finer points of OOP, a basic understanding of the differences between objects and classes is necessary. This section will go over the building blocks of classes, their different capabilities, and some of their uses.

Recognizing the Differences Between Objects and Classes

“Developers start talking about objects and classes, and they appear to be interchangeable terms. This is not the case, however.”

Right off the bat, there’s confusion in OOP: seasoned developers start talking about objects and classes, and they appear to be interchangeable terms. This is not the case, however, though the difference can be tough to wrap your head around at first.

A class, for example, is like a blueprint for a house. It defines the shape of the house on paper, with relationships between the different parts of the house clearly defined and planned out, even though the house doesn’t exist.

An object, then, is like the actual house built according to that blueprint. The data stored in the object is like the wood, wires, and concrete that compose the house: without being assembled according to the blueprint, it’s just a pile of stuff. However, when it all comes together, it becomes an organized, useful house.

Classes form the structure of data and actions and use that information to build objects. More than one object can be built from the same class at the same time, each one independent of the others. Continuing with our construction analogy, it’s similar to the way an entire subdivision can be built from the same blueprint: 150 different houses that all look the same but have different
families and decorations inside.

Structuring Classes

The syntax to create a class is pretty straightforward: declare a class using the class keyword, followed by the name of the class and a set of curly braces ({}):

<?php

class MyClass
{
    // Class properties and methods go here
}

?>

After creating the class, a new class can be instantiated and stored in a variable using the new keyword:

$obj = new MyClass;

To see the contents of the class, use var_dump():

var_dump($obj);

Try out this process by putting all the preceding code in a new file called test.php in [your local] testing folder:

<?php

class MyClass
{
	// Class properties and methods go here
}

$obj = new MyClass;

var_dump($obj);

?>

Load the page in your browser at http://localhost/test.php and the following should display:

object(MyClass)#1 (0) { }

In its simplest form, you’ve just completed your first OOP script.


Defining Class Properties

To add data to a class, properties, or class-specific variables, are used. These work exactly like regular variables, except they’re bound to the object and therefore can only be accessed using the object.

To add a property to MyClass, add the following code to your script:

<?php

class MyClass
{
    public $prop1 = "I'm a class property!";
}

$obj = new MyClass;

var_dump($obj);

?>

The keyword public determines the visibility of the property, which you’ll learn about a little later in this chapter. Next, the property is named using standard variable syntax, and a value is assigned (though class properties do not need an initial value).

To read this property and output it to the browser, reference the object from which to read and the property to be read:

echo $obj->prop1;

Because multiple instances of a class can exist, if the individual object is not referenced, the script would be unable to determine which object to read from. The use of the arrow (->) is an OOP construct that accesses the contained properties and methods of a given object.

Modify the script in test.php to read out the property rather than dumping the whole class by modifying the code as shown:

<?php

class MyClass
{
    public $prop1 = "I'm a class property!";
}

$obj = new MyClass;

echo $obj->prop1; // Output the property

?>

Reloading your browser now outputs the following:

I'm a class property!

Defining Class Methods

Methods are class-specific functions. Individual actions that an object will be able to perform are defined within the class as methods.

For instance, to create methods that would set and get the value of the class property $prop1, add the following to your code:

<?php

class MyClass
{
    public $prop1 = "I'm a class property!";

    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }

    public function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}

$obj = new MyClass;

echo $obj->prop1;

?>

Note — OOP allows objects to reference themselves using $this. When working within a method, use $this in the same way you would use the object name outside the class.

To use these methods, call them just like regular functions, but first, reference the object they belong to. Read the property from MyClass, change its value, and read it out again by making the modifications below:

<?php

class MyClass
{
    public $prop1 = "I'm a class property!";

    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }

    public function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}

$obj = new MyClass;

echo $obj->getProperty(); // Get the property value

$obj->setProperty("I'm a new property value!"); // Set a new one

echo $obj->getProperty(); // Read it out again to show the change

?>

Reload your browser, and you’ll see the following:

I'm a class property!
I'm a new property value!

“The power of OOP becomes apparent when using multiple instances of the
same class.”

<?php

class MyClass
{
    public $prop1 = "I'm a class property!";

    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }

    public function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}

// Create two objects
$obj = new MyClass;
$obj2 = new MyClass;

// Get the value of $prop1 from both objects
echo $obj->getProperty();
echo $obj2->getProperty();

// Set new values for both objects
$obj->setProperty("I'm a new property value!");
$obj2->setProperty("I belong to the second instance!");

// Output both objects' $prop1 value
echo $obj->getProperty();
echo $obj2->getProperty();

?>

When you load the results in your browser, they read as follows:

I'm a class property!
I'm a class property!
I'm a new property value!
I belong to the second instance!

As you can see, OOP keeps objects as separate entities, which makes for easy separation of different pieces of code into small, related bundles.


Magic Methods in OOP

To make the use of objects easier, PHP also provides a number of magic methods, or special methods that are called when certain common actions occur within objects. This allows developers to perform a number of useful tasks with relative ease.

Using Constructors and Destructors

When an object is instantiated, it’s often desirable to set a few things right off the bat. To handle this, PHP provides the magic method __construct(), which is called automatically whenever a new object is
created.

For the purpose of illustrating the concept of constructors, add a constructor to MyClass that will output a message whenever a new instance of the class is created:

<?php

class MyClass
{
    public $prop1 = "I'm a class property!";

    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }

    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }

    public function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}

// Create a new object
$obj = new MyClass;

// Get the value of $prop1
echo $obj->getProperty();

// Output a message at the end of the file
echo "End of file.<br />";

?>

Note__CLASS__ returns the name of the class in which it is called; this is what is known as a magic constant. There are several available magic constants, which you can read more about in the PHP manual.

Reloading the file in your browser will produce the following result:

The class "MyClass" was initiated!
I'm a class property!
End of file.

To call a function when the object is destroyed, the __destruct() magic method is available. This is useful for class cleanup (closing a database connection, for instance).

Output a message when the object is destroyed by defining the magic method
__destruct() in MyClass:

<?php

class MyClass
{
    public $prop1 = "I'm a class property!";

    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }

    public function __destruct()
    {
        echo 'The class "', __CLASS__, '" was destroyed.<br />';
    }

    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }

    public function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}

// Create a new object
$obj = new MyClass;

// Get the value of $prop1
echo $obj->getProperty();

// Output a message at the end of the file
echo "End of file.<br />";

?>

With a destructor defined, reloading the test file results in the following output:

The class "MyClass" was initiated!
I'm a class property!
End of file.
The class "MyClass" was destroyed.

“When the end of a file is reached, PHP automatically releases all resources.”

To explicitly trigger the destructor, you can destroy the object using the
function unset():

<?php

class MyClass
{
    public $prop1 = "I'm a class property!";

    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }

    public function __destruct()
    {
        echo 'The class "', __CLASS__, '" was destroyed.<br />';
    }

    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }

    public function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}

// Create a new object
$obj = new MyClass;

// Get the value of $prop1
echo $obj->getProperty();

// Destroy the object
unset($obj);

// Output a message at the end of the file
echo "End of file.<br />";

?>

Now the result changes to the following when loaded in your browser:

The class "MyClass" was initiated!
I'm a class property!
The class "MyClass" was destroyed.
End of file.

Converting to a String

To avoid an error if a script attempts to output MyClass as a string, another magic method is used called __toString().

Without __toString(), attempting to output the object as a string results in a fatal error. Attempt to use echo to output the object without a magic method in place:

<?php

class MyClass
{
    public $prop1 = "I'm a class property!";

    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }

    public function __destruct()
    {
        echo 'The class "', __CLASS__, '" was destroyed.<br />';
    }

    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }

    public function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}

// Create a new object
$obj = new MyClass;

// Output the object as a string
echo $obj;

// Destroy the object
unset($obj);

// Output a message at the end of the file
echo "End of file.<br />";

?>

This results in the following:

The class "MyClass" was initiated!

Catchable fatal error: Object of class MyClass could not be converted to string in /Applications/XAMPP/xamppfiles/htdocs/testing/test.php on line 40

To avoid this error, add a __toString() method:

<?php

class MyClass
{
    public $prop1 = "I'm a class property!";

    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }

    public function __destruct()
    {
        echo 'The class "', __CLASS__, '" was destroyed.<br />';
    }

    public function __toString()
    {
        echo "Using the toString method: ";
        return $this->getProperty();
    }

    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }

    public function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}

// Create a new object
$obj = new MyClass;

// Output the object as a string
echo $obj;

// Destroy the object
unset($obj);

// Output a message at the end of the file
echo "End of file.<br />";

?>

In this case, attempting to convert the object to a string results in a call to the getProperty() method. Load the test script in your browser to see the result:

The class "MyClass" was initiated!
Using the toString method: I'm a class property!
The class "MyClass" was destroyed.
End of file.

Tip — In addition to the magic methods discussed in this section, several others are available. For a complete list of magic methods, see the PHP manual page.


Using Class Inheritance

Classes can inherit the methods and properties of another class using the extends keyword. For instance, to create a second class that extends MyClass and adds a method, you would add the following to your test file:

<?php

class MyClass
{
    public $prop1 = "I'm a class property!";

    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }

    public function __destruct()
    {
        echo 'The class "', __CLASS__, '" was destroyed.<br />';
    }

    public function __toString()
    {
        echo "Using the toString method: ";
        return $this->getProperty();
    }

    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }

    public function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}

class MyOtherClass extends MyClass
{
    public function newMethod()
    {
        echo "From a new method in " . __CLASS__ . ".<br />";
    }
}

// Create a new object
$newobj = new MyOtherClass;

// Output the object as a string
echo $newobj->newMethod();

// Use a method from the parent class
echo $newobj->getProperty();

?>

Upon reloading the test file in your browser, the following is output:

The class "MyClass" was initiated!
From a new method in MyOtherClass.
I'm a class property!
The class "MyClass" was destroyed.

Overwriting Inherited Properties and Methods

To change the behavior of an existing property or method in the new class, you can simply overwrite it by declaring it again in the new class:

<?php

class MyClass
{
    public $prop1 = "I'm a class property!";

    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }

    public function __destruct()
    {
        echo 'The class "', __CLASS__, '" was destroyed.<br />';
    }

    public function __toString()
    {
        echo "Using the toString method: ";
        return $this->getProperty();
    }

    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }

    public function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}

class MyOtherClass extends MyClass
{
    public function __construct()
    {
        echo "A new constructor in " . __CLASS__ . ".<br />";
    }

    public function newMethod()
    {
        echo "From a new method in " . __CLASS__ . ".<br />";
    }
}

// Create a new object
$newobj = new MyOtherClass;

// Output the object as a string
echo $newobj->newMethod();

// Use a method from the parent class
echo $newobj->getProperty();

?>

This changes the output in the browser to:

A new constructor in MyOtherClass.
From a new method in MyOtherClass.
I'm a class property!
The class "MyClass" was destroyed.

Preserving Original Method Functionality While Overwriting Methods

To add new functionality to an inherited method while keeping the original method intact, use the parent keyword with the scope resolution operator (::):

<?php

class MyClass
{
    public $prop1 = "I'm a class property!";

    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }

    public function __destruct()
    {
        echo 'The class "', __CLASS__, '" was destroyed.<br />';
    }

    public function __toString()
    {
        echo "Using the toString method: ";
        return $this->getProperty();
    }

    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }

    public function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}

class MyOtherClass extends MyClass
{
    public function __construct()
    {
        parent::__construct(); // Call the parent class's constructor
        echo "A new constructor in " . __CLASS__ . ".<br />";
    }

    public function newMethod()
    {
        echo "From a new method in " . __CLASS__ . ".<br />";
    }
}

// Create a new object
$newobj = new MyOtherClass;

// Output the object as a string
echo $newobj->newMethod();

// Use a method from the parent class
echo $newobj->getProperty();

?>

This outputs the result of both the parent constructor and the new class’s constructor:

The class "MyClass" was initiated!
A new constructor in MyOtherClass.
From a new method in MyOtherClass.
I'm a class property!
The class "MyClass" was destroyed.

Assigning the Visibility of Properties and Methods

For added control over objects, methods and properties are assigned visibility. This controls how and from where properties and methods can be accessed. There are three visibility keywords: public, protected, and private. In addition to its visibility, a method or property can be declared as static, which allows them to be accessed without an instantiation of the class.

“For added control over objects, methods and properties are assigned visibility.”

Note — Visibility is a new feature as of PHP 5. For information on OOP compatibility with PHP 4, see the PHP manual page.

Public Properties and Methods

All the methods and properties you’ve used so far have been public. This means that they can be accessed anywhere, both within the class and externally.

Protected Properties and Methods

When a property or method is declared protected, it can only be accessed within the class itself or in descendant classes (classes that extend the class containing the protected method).

Declare the getProperty() method as protected in MyClass and try to access it directly from outside the class:

<?php

class MyClass
{
    public $prop1 = "I'm a class property!";

    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }

    public function __destruct()
    {
        echo 'The class "', __CLASS__, '" was destroyed.<br />';
    }

    public function __toString()
    {
        echo "Using the toString method: ";
        return $this->getProperty();
    }

    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }

    protected function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}

class MyOtherClass extends MyClass
{
    public function __construct()
    {
        parent::__construct();
		echo "A new constructor in " . __CLASS__ . ".<br />";
    }

    public function newMethod()
    {
        echo "From a new method in " . __CLASS__ . ".<br />";
    }
}

// Create a new object
$newobj = new MyOtherClass;

// Attempt to call a protected method
echo $newobj->getProperty();

?>

Upon attempting to run this script, the following error shows up:

The class "MyClass" was initiated!
A new constructor in MyOtherClass.

Fatal error: Call to protected method MyClass::getProperty() from context '' in /Applications/XAMPP/xamppfiles/htdocs/testing/test.php on line 55

Now, create a new method in MyOtherClass to call the getProperty() method:

<?php

class MyClass
{
    public $prop1 = "I'm a class property!";

    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }

    public function __destruct()
    {
        echo 'The class "', __CLASS__, '" was destroyed.<br />';
    }

    public function __toString()
    {
        echo "Using the toString method: ";
        return $this->getProperty();
    }

    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }

    protected function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}

class MyOtherClass extends MyClass
{
    public function __construct()
    {
        parent::__construct();
		echo "A new constructor in " . __CLASS__ . ".<br />";
    }

    public function newMethod()
    {
        echo "From a new method in " . __CLASS__ . ".<br />";
    }

    public function callProtected()
    {
        return $this->getProperty();
    }
}

// Create a new object
$newobj = new MyOtherClass;

// Call the protected method from within a public method
echo $newobj->callProtected();

?>

This generates the desired result:

The class "MyClass" was initiated!
A new constructor in MyOtherClass.
I'm a class property!
The class "MyClass" was destroyed.

Private Properties and Methods

A property or method declared private is accessible only from within the class that defines it. This means that even if a new class extends the class that defines a private property, that property or method will not be available at all within the child class.

To demonstrate this, declare getProperty() as private in MyClass, and attempt to call callProtected() from
MyOtherClass:

<?php

class MyClass
{
    public $prop1 = "I'm a class property!";

    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }

    public function __destruct()
    {
        echo 'The class "', __CLASS__, '" was destroyed.<br />';
    }

    public function __toString()
    {
        echo "Using the toString method: ";
        return $this->getProperty();
    }

    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }

    private function getProperty()
    {
        return $this->prop1 . "<br />";
    }
}

class MyOtherClass extends MyClass
{
    public function __construct()
    {
        parent::__construct();
        echo "A new constructor in " . __CLASS__ . ".<br />";
    }

    public function newMethod()
    {
        echo "From a new method in " . __CLASS__ . ".<br />";
    }

    public function callProtected()
    {
        return $this->getProperty();
    }
}

// Create a new object
$newobj = new MyOtherClass;

// Use a method from the parent class
echo $newobj->callProtected();

?>

Reload your browser, and the following error appears:

The class "MyClass" was initiated!
A new constructor in MyOtherClass.

Fatal error: Call to private method MyClass::getProperty() from context 'MyOtherClass' in /Applications/XAMPP/xamppfiles/htdocs/testing/test.php on line 49

Static Properties and Methods

A method or property declared static can be accessed without first instantiating the class; you simply supply the class name, scope resolution operator, and the property or method name.

“One of the major benefits to using static properties is that they keep their stored values for the duration of the script.”

To demonstrate this, add a static property called $count and a static method called plusOne() to MyClass. Then set up a do...while loop to output the incremented value of $count as long as the value is less than 10:

<?php

class MyClass
{
    public $prop1 = "I'm a class property!";

    public static $count = 0;

    public function __construct()
    {
        echo 'The class "', __CLASS__, '" was initiated!<br />';
    }

    public function __destruct()
    {
        echo 'The class "', __CLASS__, '" was destroyed.<br />';
    }

    public function __toString()
    {
        echo "Using the toString method: ";
        return $this->getProperty();
    }

    public function setProperty($newval)
    {
        $this->prop1 = $newval;
    }

    private function getProperty()
    {
        return $this->prop1 . "<br />";
    }

    public static function plusOne()
    {
        return "The count is " . ++self::$count . ".<br />";
    }
}

class MyOtherClass extends MyClass
{
    public function __construct()
    {
        parent::__construct();
        echo "A new constructor in " . __CLASS__ . ".<br />";
    }

    public function newMethod()
    {
        echo "From a new method in " . __CLASS__ . ".<br />";
    }

    public function callProtected()
    {
        return $this->getProperty();
    }
}

do
{
    // Call plusOne without instantiating MyClass
    echo MyClass::plusOne();
} while ( MyClass::$count < 10 );

?>

Note — When accessing static properties, the dollar sign
($) comes after the scope resolution operator.

When you load this script in your browser, the following is output:

The count is 1.
The count is 2.
The count is 3.
The count is 4.
The count is 5.
The count is 6.
The count is 7.
The count is 8.
The count is 9.
The count is 10.

Commenting with DocBlocks

“The DocBlock commenting style is a widely
accepted method of documenting classes.”

While not an official part of OOP, the DocBlock commenting style is a widely accepted method of documenting classes. Aside from providing a standard for
developers to use when writing code, it has also been adopted by many of the most popular software development kits (SDKs), such as Eclipse and NetBeans, and will be used to generate code hints.

A DocBlock is defined by using a block comment that starts with an additional asterisk:

/**
 * This is a very basic DocBlock
 */

The real power of DocBlocks comes with the ability to use tags, which start with an at symbol (@) immediately followed by the tag name and the value of the tag. DocBlock tags allow developers to define authors of a file, the license for a class, the property or method information, and other useful information.

The most common tags used follow:

  • @author: The author of the current element (which might be a class, file, method, or any bit of code) are listed using this tag. Multiple author tags can be used in the same DocBlock if more than one author is credited. The format for the author name is John Doe <john.doe@email.com>.
  • @copyright: This signifies the copyright year and name of the copyright holder for the current element. The format is 2010 Copyright Holder.
  • @license: This links to the license for the current element. The format for the license information is
    http://www.example.com/path/to/license.txt License Name.
  • @var: This holds the type and description of a variable or class property. The format is type element description.
  • @param: This tag shows the type and description of a function or method parameter. The format is type $element_name element description.
  • @return: The type and description of the return value of a function or method are provided in this tag. The format is type return element description.

A sample class commented with DocBlocks might look like this:

<?php

/**
 * A simple class
 *
 * This is the long description for this class,
 * which can span as many lines as needed. It is
 * not required, whereas the short description is
 * necessary.
 *
 * It can also span multiple paragraphs if the
 * description merits that much verbiage.
 *
 * @author Jason Lengstorf <jason.lengstorf@ennuidesign.com>
 * @copyright 2010 Ennui Design
 * @license http://www.php.net/license/3_01.txt PHP License 3.01
 */
class SimpleClass
{
    /**
     * A public variable
     *
     * @var string stores data for the class
     */
    public $foo;

    /**
     * Sets $foo to a new value upon class instantiation
     *
     * @param string $val a value required for the class
     * @return void
     */
    public function __construct($val)
    {
        $this->foo = $val;
    }

    /**
     * Multiplies two integers
     *
     * Accepts a pair of integers and returns the
     * product of the two.
     *
     * @param int $bat a number to be multiplied
     * @param int $baz a number to be multiplied
     * @return int the product of the two parameters
     */
    public function bar($bat, $baz)
    {
        return $bat * $baz;
    }
}

?>

Once you scan the preceding class, the benefits of DocBlock are apparent: everything is clearly defined so that the next developer can pick up the code and never have to wonder what a snippet of code does or what it should contain.


Comparing Object-Oriented and Procedural Code

There’s not really a right and wrong way to write code. That being said, this section outlines a strong argument for adopting an object-oriented approach in software development, especially in large applications.


Reason 1: Ease of Implementation

“While it may be daunting at first, OOP actually provides an easier approach to dealing with data.”

While it may be daunting at first, OOP actually provides an easier approach to dealing with data. Because an object can store data internally, variables don’t need to be passed from function to function to work properly.

Also, because multiple instances of the same class can exist simultaneously, dealing with large data sets is infinitely easier. For instance, imagine you have two people’s information being processed in a file. They need names, occupations, and ages.

The Procedural Approach

Here’s the procedural approach to our example:

<?php

function changeJob($person, $newjob)
{
    $person['job'] = $newjob; // Change the person's job
    return $person;
}

function happyBirthday($person)
{
    ++$person['age']; // Add 1 to the person's age
    return $person;
}

$person1 = array(
    'name' => 'Tom',
    'job' => 'Button-Pusher',
    'age' => 34
);

$person2 = array(
    'name' => 'John',
    'job' => 'Lever-Puller',
    'age' => 41
);

// Output the starting values for the people
echo "<pre>Person 1: ", print_r($person1, TRUE), "</pre>";
echo "<pre>Person 2: ", print_r($person2, TRUE), "</pre>";

// Tom got a promotion and had a birthday
$person1 = changeJob($person1, 'Box-Mover');
$person1 = happyBirthday($person1);

// John just had a birthday
$person2 = happyBirthday($person2);

// Output the new values for the people
echo "<pre>Person 1: ", print_r($person1, TRUE), "</pre>";
echo "<pre>Person 2: ", print_r($person2, TRUE), "</pre>";

?>

When executed, the code outputs the following:

Person 1: Array
(
    [name] => Tom
    [job] => Button-Pusher
    [age] => 34
)
Person 2: Array
(
    [name] => John
    [job] => Lever-Puller
    [age] => 41
)
Person 1: Array
(
    [name] => Tom
    [job] => Box-Mover
    [age] => 35
)
Person 2: Array
(
    [name] => John
    [job] => Lever-Puller
    [age] => 42
)

While this code isn’t necessarily bad, there’s a lot to keep in mind while coding. The array of the affected person’s attributes must be passed and returned from each function call, which leaves margin for error.

To clean up this example, it would be desirable to leave as few things up to the developer as possible. Only absolutely essential information for the current operation should need to be passed to the functions.

This is where OOP steps in and helps you clean things up.

The OOP Approach

Here’s the OOP approach to our example:

<?php

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

    public function __construct($name, $job, $age)
    {
        $this->_name = $name;
        $this->_job = $job;
        $this->_age = $age;
    }

    public function changeJob($newjob)
    {
        $this->_job = $newjob;
    }

    public function happyBirthday()
    {
        ++$this->_age;
    }
}

// Create two new people
$person1 = new Person("Tom", "Button-Pusher", 34);
$person2 = new Person("John", "Lever Puller", 41);

// Output their starting point
echo "<pre>Person 1: ", print_r($person1, TRUE), "</pre>";
echo "<pre>Person 2: ", print_r($person2, TRUE), "</pre>";

// Give Tom a promotion and a birthday
$person1->changeJob("Box-Mover");
$person1->happyBirthday();

// John just gets a year older
$person2->happyBirthday();

// Output the ending values
echo "<pre>Person 1: ", print_r($person1, TRUE), "</pre>";
echo "<pre>Person 2: ", print_r($person2, TRUE), "</pre>";

?>

This outputs the following in the browser:

Person 1: Person Object
(
    [_name:private] => Tom
    [_job:private] => Button-Pusher
    [_age:private] => 34
)

Person 2: Person Object
(
    [_name:private] => John
    [_job:private] => Lever Puller
    [_age:private] => 41
)

Person 1: Person Object
(
    [_name:private] => Tom
    [_job:private] => Box-Mover
    [_age:private] => 35
)

Person 2: Person Object
(
    [_name:private] => John
    [_job:private] => Lever Puller
    [_age:private] => 42
)

There’s a little bit more setup involved to make the approach object oriented, but after the class is defined, creating and modifying people is a breeze; a person’s information does not need to be passed or returned from methods, and only absolutely essential information is passed to each method.

“OOP will significantly reduce your workload if implemented properly.”

On the small scale, this difference may not seem like much, but as your applications grow in size, OOP will significantly reduce your workload if implemented properly.

TipNot everything needs to be object oriented. A quick function that handles something small in one place inside the application does not necessarily need to be wrapped in a class. Use your best judgment when deciding between object-oriented and procedural approaches.


Reason 2: Better Organization

Another benefit of OOP is how well it lends itself to being easily packaged and cataloged. Each class can generally be kept in its own separate file, and if a uniform naming convention is used, accessing the classes is extremely simple.

Assume you’ve got an application with 150 classes that are called dynamically through a controller file at the root of your application filesystem. All 150 classes follow the naming convention class.classname.inc.php and reside in the inc folder of your application.

The controller can implement PHP’s __autoload() function to dynamically pull in only the classes it needs as they are called, rather than including all 150 in the controller file just in case or coming up with some clever way of including the files in your own code:

<?php
    function __autoload($class_name)
    {
        include_once 'inc/class.' . $class_name . '.inc.php';
    }
?>

Having each class in a separate file also makes code more portable and easier to reuse in new applications without a bunch of copying and pasting.


Reason 3: Easier Maintenance

Due to the more compact nature of OOP when done correctly, changes in the code are usually much easier to spot and make than in a long spaghetti code procedural implementation.

If a particular array of information gains a new attribute, a procedural piece of software may require (in a worst-case scenario) that the new attribute be added to each function that uses the array.

An OOP application could potentially be updated as easily adding the new property and then adding the methods that deal with said property.

A lot of the benefits covered in this section are the product of OOP in combination with DRY programming practices. It is definitely possible to create easy-to-maintain procedural code that doesn’t cause nightmares, and it is equally possible to create awful object-oriented code. [Pro PHP and jQuery] will attempt to demonstrate a combination of good coding habits in conjunction with OOP to generate clean code that’s easy to read and maintain.


Summary

At this point, you should feel comfortable with the object-oriented programming style. Learning OOP is a great way to take your programming to that next level. When implemented properly, OOP will help you produce easy-to-read, easy-to-maintain, portable code that will save you (and the developers who work with you) hours of extra work. Are you stuck on something that wasn’t covered in this article? Are you already using OOP and have some tips for beginners? Share them in the comments!

Author’s Note — This tutorial was an excerpt from Pro PHP and jQuery (Apress, 2010).

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • Daniel

    After understanding the concepts of OOP, take a look at the SPL classes.

  • Cristian matos

    Great tutorial!

  • http://butenas.com Ignas

    Nice work. Will be useful for the beginners. I just skimmed this and found some good points. It seems that finally nettuts comming back and stopped posting crap :)

    • Colby

      + 1

  • http://www.spyndle.com Kreg Steppe

    A simple tip. If you have short_open_tag enabled in your php.ini:

    to do this…

    <a href="”>Link

    You can do it like this

    <a href="”>Link

    It’s a quick shortcut for outputting a variable.

  • http://spyndle.com Kreg Steppe

    This is a fix for the previous comment:

    A simple tip. If you have short_open_tag enabled in your php.ini:

    to do this…

    <a href="”>Link

    You can do it like this

    <a href="”>Link

    It’s a quick shortcut for outputting a variable. (just remove the extra spaces in there)

  • http://spyndle.com Kreg Steppe

    Crap. Can’t post my shortcut tip. Anyways…you can find it here.
    http://php.net/manual/en/function.echo.php

  • Piedro

    Very good tutorial, it’s a easy starting tutorial for developpers who don’t use OOP.
    Keep up the good work!

  • http://struys.ca Ken Struys

    Be careful when using unset variables in boolean expressions.

    if($foo) { … } // If $foo is not set then the block wont be executed as expected but note that if $foo is 0 the block will also not be executed.

    These bugs can be really irritating. If you want to be safe, “say what you mean”: is_null, isset, is_numeric, etc.

  • Achmed-Abdullah-Mohammed-Hassan-Ali-Mehmet-Yusup

    Wow ! I’ve been waiting for this tutoral ever since it came to my mind to try some OO-PHP and now its here =). Only got 1 question for u guys:
    Is “$obj = new MyClass;” equal to “$obj = new MyClass();”? i.e Should I use “()” after the class name?

    Once again thanks for one of the best tutorials in a very long time.

    • JohnGlave

      They’re both the same, but you would use $obj = new MyClass(“My parameter”); if you wanted to pass in parameters (like a function), which is not covered in the tutorial.

      Since I couldn’t find a good tutorial on the subject you can define parameters for the class in the constructor, like so:

      class MyClass {
      public function __construct($myParameter) {
      echo $myParameter;
      }
      }

      $obj = new MyClass(“Hello, World!”); // Should echo “Hello, World!”.

      Hope this helped!

    • Ian Graham

      The () are only needed if you are passing parameters to the constructor

  • KanZonk

    Need the next series of OOP PHP……..

    Thanks for this tutorial, and waiting for next series :D

  • pullmand

    What timing! I was literally about to start learning more about PHP OOP yesterday and then this post comes along.

  • http://www.broof.de BroOf

    Thank you for this huge tutorial. I think you covered everything a beginner should know.

  • Karp13

    Thank you!! This all just kind of clicked. I think your book may be a little above my head, but I do look forward to reading it once I have had more time to learn the basics.

    • http://ennuidesign.com Jason Lengstorf

      Glad it helped! If you want to get caught up and feel comfortable in Pro PHP and jQuery, you could grab my other book, PHP for Absolute Beginners which would take your skills up to a high enough level to easily work through the new book.

  • Richard

    Nice intro to ooPHP.

  • http://www.ericbieller.com Eric

    Great tutorial. Awesome for beginners but it actually helped me refresh my memory on a couple of techniques I hadn’t used in a while.

  • http://www.wwebz.com/ Rehaan

    Thanks you for a detailed tutorial as a beginner it helps me a lot :)

  • Gaz

    This is awesome, nice post. I like inclusion of documentation too, very apt

  • http://markpopkes.com Mark

    I’ve been wanting to tap into OOP for awhile now, especially since I’ve come across CodeIgniter, but OOP has always seemed to daunting! This tut was great — easy to follow and comprehend. I hope to see more OOP tuts here and maybe even a Premium tutorial! Thanks.

  • http://freecss.info CSS Tutorials

    Great tutorial as usual. Well written content. I contemplated writing a tutorial for nettuts but reckon my writing may let me down.

    • http://ennuidesign.com Jason Lengstorf

      Practice makes perfect. :)

      • http://www.phphunger.com/ phphunger

        simple correction….practice doesn’t make perfect……”oNLY pERFECT pRACTICE mAKES pERFECT”

  • http://www.anthonymclin.com Anthony McLin

    This is a great refresher for OOP in PHP, although I think it’s probably a bit obtuse still for beginners to OOP. It’s also very long, and would probably have been better if broken up into a multi-part tutorial that would have dovetailed very nicely into yesterday’s Design Patterns tutorial.

  • http://creatia.us/ Ryan Doss

    Fantabulous Tutorial ; ) beautifully written, perfect examples. I learned a GREAT deal from this. Thanks m8!

  • http://www.juancarlosrois.com Juan C. Rois

    This is awesome, I’ve been waiting for an in-depth tutorial about this, Jeffery Way has talked about OOP in PHP in many of his tutorials (correct me if I’m wrong, and by the way Jeff, your tuts rock), and because of him I’ve been able to grasp the concept, but your tutorial will help me a lot, now that I have a project in my mind that would benefit greatly from OOP.
    I can’t wait to get home tonight and read the whole article.
    Thanks so very much for posting this article, and I’ll also buy your book as well.

    Thanks again.

    • http://www.juancarlosrois.com Juan C. Rois

      @Jason – is your book also OOP oriented? I quickly read the table of contents and I could not see any reference to OOP?
      I’m still buying it but I’m curious?

      • http://ennuidesign.com Jason Lengstorf

        @Juan – Yes, all the PHP in Pro PHP and jQuery is OOP-based. Glad you enjoyed the tutorial, and thanks for buying the book!

  • http://alteredaspect.info Rob MacKay

    Awesome yet again :) Nice one dude.

    Gratz on the new book release

    My tip: Try and take more time to plan the methods in your class before you begin coding it – make them work together instead of writing specific ones for specific tasks, else you end up with hundreds (voice of experience lol) Also – it’s not that hard, you will always – always get better – you have a brain so nothing is impossible.

  • http://www.falkencreative.com Benjamin Falk

    One of the best OOP introductions I’ve seen. Thanks for writing!

  • Dan

    Very nice tutorial. I haven’t learned OOP in PHP yet because it’s scary but hopefully this should do it.

    I am also buying Pro PHP and jQuery… is this a good book for OOP?

    • http://ennuidesign.com Jason Lengstorf

      @Dan – This article is a sample chapter from Pro PHP and jQuery. The entire back-end of the application built in the book is OOP-based, so it will give you a hands-on experience with OOP that will help you feel comfortable using these techniques in your own scripts.

      Thanks!

      • Dan

        Well, I bet you know what book I am buying now! Hehe, gonna order your book later today! ;)

        Thanks Jason Lengstorf! Nice last name, by the way!

  • http://www.mpmwebdesign.com max

    Just curious, why are the class properties public?
    everything I’ve learned previously taught me to make instance variables private?

    • http://ennuidesign.com Jason Lengstorf

      That’s a good practice. If you can get away with private, that’s a good idea. Use your discretion when writing classes; define methods and properties with the minimum required level of visibility.

      Good luck!

  • http://any.onecancode.com/ Philip Schweiger

    I started getting into OOP a bit under a year ago. I like to combine OOP with try/catch blocks, so I get both flexibility in architecture thanks to OOP, but also flexibility in dealing with error handling and debugging. I don’t want to make this a super long comment, but briefly I’ve found the following combo triad of technologies/techniques super-helpful:

    - PHP Object-oriented programming +
    - PHP try/catch blocks +
    - PHP simpletest unit testing tool

  • Andy King

    This is an excellent tutorial for a number of reasons. The first is that it breaks the subject into easily understandable chunks (much like programming itself should do). And the second is that it addresses one of the most common reasons heard from beginners (and repeated in some of these comments) about why they haven’t yet adopted OOP: “it’s too scary”. One of the “scary” things is how much work (on the surface) a programmer seems to have to do to organize code in this fashion — procedural coding for some SEEMS to be less work than putting every task to be performed into a class.

    But things like the following sentence, which Jason so wisely inserted, take away this aspect of a beginner’s worry:
    “Tip — Not everything needs to be object oriented. A quick function that handles something small in one place inside the application does not necessarily need to be wrapped in a class.”

    I could quote other examples of the ways Jason has “defanged” the beast. All in all, a well thought-out tutorial for its audience. Congrats, Jason and NetTuts+.

  • http://www.xhtml.si SpinX

    my tip:

    You can dinamically call functions like this:

    $function = “myAwecomeFunc”;

    $function();

  • adrian

    question: do you have to use the public/private keywords? I know in codeigniter you don’t have to use them but maybe it just uses some hack to do that. does omitting the public/private keyword fallback to public (or maybe private)

    • JohnGlave

      If you omit public/protected/private, it defaults to public, see http://php.net/manual/en/language.oop5.visibility.php .

    • http://ennuidesign.com Jason Lengstorf

      If you don’t set visibility (public/private/protected) the property or method will default to public. However, I would strongly recommend that you set visibility in your scripts. You can read more in the PHP Manual entry on visibility in OOP for PHP5.

    • http://vim.gentle.ro vimishor

      CodeIgniter is using “var” for compatibility with PHP4. It will work in PHP5, but will raise an E_STRICT warning up to 5.3. In newer versions since 5.3 “var” is deprecated. If you have PHP5, don’t use “var”.

  • http://vividpencil.net Serge

    Useful piece of advice on naming variables in PHP.

    At the beginning of a variable you can add three letters which reflect its type and of course the variable’s name should be self explanatory:

    $intXXXXX – for integers ($intPhoneNumber, $intUserID, $intYear, etc…)
    $strXXXXX- for strings ($strUserName, $strCarBrand, $strCountry, etc…)
    $arrXXXXX- for arrays ($arrMonths, $arrSystemModules, $arrGalleries, etc…)
    $dblXXXX or $fltXXXX – for floats ($fltPrice, $dblSubTotal, etc…)

    And please don’t forget, that variables in PHP are case sensitive, $strMyName doesn’t equal to $strmyname.

    Cheers!

  • http://vidarvestnes.blogspot.com Vidar Vestnes

    Thanks for a nice article! Just a small thing about one of the quotes:

    “When the end of a file is reached, PHP automatically releases all resources.”

    Im not sure if that is 100% correct. Global resources like variables in a class is not released before the end of the execution / request. Example

    a = “hello”;
    $my_obj->b = “world”;
    ?>

    • http://ennuidesign.com Jason Lengstorf

      That’s correct. I was unclear in the article; all resources are released at the end of execution of the file being executed. Included resources will be available in the file being executed (i.e. if you load bar.php into foo.php, all global variables set in bar.php will be available until the end of foo.php is reached unless destroyed manually).

  • http://vidarvestnes.blogspot.com Vidar Vestnes

    Oops.. the example got broken … < <

  • http://vidarvestnes.blogspot.com Vidar Vestnes

    … repost… hopefully with the example incldued…

    <?php // Filename a.php
    $my_array = array(“a”,”b”,”c”);
    $my_obj = new stdClass();
    $my_obj->a = “hello”;
    $my_obj->b = “world”;
    ?>

    <?php // Filename b.php
    include ‘a.php’;
    // Here we can see that resources from file a.php still exists!
    var_dump($my_array, $my_obj);
    ?>

  • http://www.tasarimrehberi.net Nurettin

    Thanks very good php document

  • commenter

    Errr, obviously they still exist they were run in the same process, i mean, you included a.php from that file ofcourse variables are passed, people dont use include for html only, infact that itself is bad practice in ways :/

    I suggest you stop pasting PHP articles onto your blog and go out learning.

  • http://www.dangermoose.co.uk flashmac

    These are the kind of quality tuts that have been missing of late. Top banana.

  • http://www.scriptplazza.com/ ScriptPlazza

    Useful tutorials , thanks!

  • joe

    Like what most folk have said already, GREAT TUT! I think more of this type of tutorial should come after all this is what made nettuts the site go the most. Hope to see more intermediate stuff fly here: spl, polymorphism, aggregation things of that sort. Just a thought though why haven’t we had any python tuts?

    Great work guys

  • http://ajaxee.xtreemhost.com/ gabu

    NIce,

    I am a newbie in oops in php,
    Great tutorial & I enjoy the whole tut.
    Looking for the next series,

    Thanks,

  • Notta

    Thanks for this post. I’m loving all these PHP and MYSQL guides as of late. Please keep them coming.

  • http://www.visual-blade.com Daquan Wright

    Great looking tut, although I can’t be bothered reading all of it right now.

  • Martin

    Nice OOP intro, well written and concise considering how much is packed in there. Best Nettuts tutorial in a while.

  • http://www.dreamdust.net/ Can

    Nice tutorial, here is my tip;

    You can use
    or
    instead of using
    or

  • http://www.dreamdust.net/ Can

    Hmm tip is not shown. Any suggestions?

  • Muhammad Omar

    Very good tutorial, but i think that you can ditch the function unset() because i think since PHP version 5.3 there is an auto garbage collection, so you won’t need this, am i wrong?

  • http://www.jsxtech.com Jaspal Singh

    Great tutorial on Object-Oriented PHP for beginners.
    Thanks for sharing.

  • Latavish Gardner

    Boy the good old days of beginner php. The memories.

  • http://jon.breitenbucher.net Jon Breitenbucher

    I think this is the first presentation of OOP in PHP that has made sense to me. Thanks for a very nice tip.

  • Keshav

    Very Impressive Tutorial…i m waiting for next…

    please elaborate of self keyword in your tutorial where u used…because it is confusing to use self..

    self keyword is used for static method and property or we can use it anywhere?

    • http://ennuidesign.com Jason Lengstorf

      The self keyword is for static methods and properties only. It won’t work when referencing other methods or properties.