The PHP Anthology Volume 1, Chapter 2 - Object Oriented PHP

The object oriented paradigm is an approach to programming that’s intended to encourage the development of maintainable and well structured applications. Many PHP coders regard object oriented programming (OOP) as some kind of mystic art, given that frequently, examples of PHP look only at procedural approaches to problem solving. (Note that procedural programming is the name given to non-object oriented programming. All the code we’ve seen in this book so far has been procedural in nature.)

This is a shame, as there is much to be gained from adopting an object oriented approach to developing PHP applications, perhaps the most important being code reuse. A well written piece of object oriented code can easily be employed to solve the same problem in other projects; we can simply slot it in whenever we need it. There is a growing number of object oriented code repositories, such as PEAR and PHP Classes, which can save you from hours of work spent solving well charted problems, and leave you free to focus on the specifics of your application.

In this chapter, you’ll gain a practical grounding in writing object oriented PHP – and there’ll be plenty of opportunities to get your hands dirty. There are many ways to teach OOP, and the topic provides endless room for discussion. In my opinion, the best approach is to dive in head first, seeing how procedural tasks can be accomplished with classes in PHP, and adding the theory as we go. This is the approach we’ll take in this chapter. Throughout both volumes of The PHP Anthology, I’ll be using OOP, where appropriate, which should give you further examples to study. In particular, Chapter 7, Design Patterns should provide some insight into why OOP is an effective way to structure your applications.

In practice, learning to use the object model provided by PHP requires us to achieve two goals, which usually have to be undertaken simultaneously:

  • You’ll need to learn the PHP class syntax and object oriented terminology.
  • You must make the “mental leap” from procedural to object oriented code.

The first step is easy. It’s the subject of the next solution, and further examples appear in later solutions that look at more advanced subjects.

The second step, the “mental leap”, is both easy and challenging. Once you achieve it, you will no longer think about long lists of tasks that a single script should accomplish; instead, you’ll see programming as the putting together of a set of tools to which your script will delegate work.

Jumping ahead a little – to give you a taste of things to come – here’s a simple example that should be familiar to anyone who’s worked with PHP for more than a week: connecting to MySQL and fetching some data. A common procedural approach looks like this:

<?php   // Procedural Example 

// Connect to MySQL   $connection = mysql_connect('localhost', 'harryf', 'secret'); 

// Select desired database   mysql_select_db('sitepoint', $connection); 

// Perform a query selecting five articles   $sql = 'SELECT * FROM articles LIMIT 0,5';   $result = mysql_query($sql, $connection); 

// Display the results   while ($row = mysql_fetch_array($result)) {     // Display results here   }   ?>

In the above script, we’ve called directly PHP’s MySQL functions, which act on the variables we pass to them. This generally results in our getting back a new variable with which we can perform further work.

An object oriented approach to solving the same problem might look like this:

<?php   // OOP Example 

// Include MySQL class   require_once 'Database/MySQL.php'; 

// Instantiate MySQL class, connect to MySQL and select database   $db = new MySQL('localhost', 'harryf', 'secret', 'sitepoint'); 

// Perform a query selecting five articles   $sql = 'SELECT * FROM articles LIMIT 0,5';   $result = $db->query($sql); // Creates a MySQLResult object 

// Display the results   while ($row = $result->fetch()) {     // Display results here   }   ?>

The detail of dealing with MySQL using PHP’s MySQL functions has now been delegated to an object that’s created from the MySQL class (which we’ll use frequently throughout this book, and which is constructed in Chapter 3, PHP and MySQL). Although this example may not make entirely clear the advantages of OOP, given that, in terms of the amount of code, it’s very similar to the first example, what it does show is that some of the original script’s complexity is now being taken care of by the MySQL class.

For example, we now no longer need to perform two steps to connect to the MySQL server, and then select a database; rather, we can handle both steps in one when we create the MySQL object. Also, should we later wish to have the script fetch the results from a different database, such as PostgreSQL, we could use the relevant class that provided the same application programming interface (API) as the MySQL class – and, to do so, we’d only need to change a single line of the above example. We’ll do exactly that in Chapter 7, Design Patterns.

The object oriented approach really shows its worth in situations in which objects interact with each other. I’ll leave further discussion of that to the solutions in this chapter, but it’s an important concept. As you become fluent in object oriented programming, you’ll find that writing complex applications becomes as easy as putting together blocks of Lego.

I’ll introduce the occasional Unified Modelling Language (UML) class diagram in this discussion. UML is a standard for describing object oriented programs with images. Don’t worry if you haven’t come across UML before; the relationship between the diagrams and the code will speak for itself.

What are the basics of object oriented PHP?

Assuming you have no knowledge of OOP, the best place to start is with the basic PHP syntax for classes. You can think of a class simply as a collection of functions and variables.

Read The Fine Manual

The PHP manual contains a wealth of information on OOP:

Here, we’ll develop a simple example that could help us generate HTML, which will demonstrate the basics of classes and objects in PHP. This isn’t intended to be an example of great design; it’s simply a primer in PHP syntax. Let’s begin with a procedural script that builds a Web page. Then we’ll gradually turn it into a PHP class:

Example 2.1. 1.php

<?php    // Generates the top of the page    function addHeader($page, $title)    {      $page .= <<<EOD    <html>    <head>    <title>$title</title>    </head>    <body>    <h1 align="center">$title</h1>    EOD;      return $page;    }  

// Generates the bottom of the page    function addFooter($page, $year, $copyright)    {      $page .= <<<EOD    <div align="center">&copy; $year $copyright</div>    </body>    </html>    EOD;      return $page;    }  

// Initialize the page variable    $page = '';  

// Add the header to the page    $page = addHeader($page, 'A Prodecural Script');  

// Add something to the body of the page    $page .= <<<EOD    <p align="center">This page was generated with a procedural    script</p>    EOD;  

// Add the footer to the page    $page = addFooter($page, date('Y'), 'Procedural Designs Inc.');  

// Display the page    echo $page;    ?>

Of note in this example is our first look at heredoc syntax, which is an alternative method of writing PHP strings. Instead of surrounding the text with quotes, you begin it with <<<EOD and a new line, and end it with a new line and then EOD. The PHP Manual can offer more detail on this if you’re curious.

This procedural example uses two functions, addHeader and addFooter, along with a single global variable, $page. Perhaps this isn’t a far cry from procedural scripts you’ve written yourself; maybe you’ve included in every page a file that contains functions such as addHeader and addFooter.

But how do we refactor the above code to take on an object oriented form? (Refactoring is the process of restructuring code without actually changing what it does. This is usually done to ease future maintenance and expansion of the code that would be hindered by its current structure.)

First, we need a class into which we can place the two functions, addHeader and addFooter:

Example 2.2. 2.php (excerpt)

<?php    // Page class    class Page {      // Generates the top of the page      function addHeader($page, $title)      {        $page .= <<<EOD    <html>    <head>    <title>$title</title>    </head>    <body>    <h1 align="center">$title</h1>    EOD;        return $page;      }  

// Generates the bottom of the page      function addFooter($page, $year, $copyright)      {        $page .= <<<EOD    <div align="center">&copy; $year $copyright</div>    </body>    </html>    EOD;        return $page;      }    }

Using the PHP keyword class, we can group the two functions, addHeader and addFooter, within the class. Functions placed inside a class are known as member functions, or, more commonly, methods. Unlike normal functions, methods must be called as part of the class:

Example 2.3. 2.php (excerpt)

// Initialize the page variable    $page = '';  

// Add the header to the page    $page = Page::addHeader($page, 'A Script Using Static Methods');  

// Add something to the body of the page    $page .= <<<EOD    <p align="center">This page was generated with static class    methods</p>    EOD;  

// Add the footer to the page    $page = Page::addFooter($page, date('Y'), 'Static Designs Inc.');  

// Display the page    echo $page;    ?>

Here, we’ve called the class methods addHeader and addFooter using the :: operator. The script is practically the same as before; however, instead of calling our functions directly, we need to call them as shown here:

$page = Page::addHeader($page, 'A Script Using Static Methods');

Although this isn’t a big improvement, it does let us collect our functions together by their job description. This allows us to call different functions by the same name, each nested separately inside a different class.

Static Methods

So far, we’ve only used a class as a container for related functions. In object oriented parlance, functions that are designed to work this way are called static methods.

Actually, compared to most methods, static methods are about as boring as they sound. In the sections below, we’ll see how you can really flex your object oriented muscles with some fully-fledged methods.

Classes and Objects

A class is a “blueprint” for an object. That is, unlike a function that you’d declare and use, a class merely describes a type of object. Before you can do useful work with it, you need to create an object – an instance of the class – using a process called instantiation. Once you have an object, you can call the methods that are defined in the class.

Classes don’t contain only functions – they can also contain variables. To make the Page class we developed above more useful, we might want to group some variables with the methods, then instantiate the class into an object. Here’s the code for the revamped Page class; join me below for the explanation:

Example 2.4. 3.php (excerpt)

<?php     // Page class     class Page {   

// Declare a class member variable       var $page;   

// The constructor function       function Page()       {         $this->page = '';       }   

// Generates the top of the page       function addHeader($title)       {         $this->page .= <<<EOD     <html>     <head>     <title>$title</title>     </head>     <body>     <h1 align="center">$title</h1>     EOD;       }   

// Adds some more text to the page       function addContent($content)       {         $this->page .= $content;       }   

// Generates the bottom of the page       function addFooter($year, $copyright)       {         $this->page .= <<<EOD     <div align="center">&copy; $year $copyright</div>     </body>     </html>     EOD;       }   

// Gets the contents of the page       function get()       {         return $this->page;       }     }

The Page class has become a lot more useful in this version of the example. First of all, we’ve added a member variable (also called a field), in which to store the HTML:

  // Declare a class member variable       var $page;

The PHP keyword var is used to declare variables in classes. We can also assign values to variables as we declare them, but we cannot place function calls in the declaration. For example:

  // This is allowed       var $page = '';   

// This is NOT allowed       var $page = strtolower('HELLO WORLD');

After the variable declaration, we have a special method called the constructor. This method is automatically executed when the class is instantiated. The constructor function must always have the same name as the class.

Constructors have no return value

A constructor cannot return any value. It is used purely to set up the object in some way as the class is instantiated. If it helps, think of the constructor as a function that automatically returns the object once it has been set up, so there’s no need for you to supply a return value yourself.

That said, you may still use the return command with no specified value to terminate the constructor immediately, if needed.

Inside the constructor we’ve used a special variable, $this:

  // The constructor function       function Page()       {         $this->page = '';       }

Within any method (including the constructor) $this points to the object in which the method is running. It allows the method to access the other methods and variables that belong to that particular object. The -> (arrow) operator that follows $this is used to point at a property or method that’s named within the object.

In the example above, the constructor assigns an empty string value to the $page member variable we declared at the start. The idea of the $this variable may seem awkward and confusing to start with, but it’s a common strategy employed by other programming languages, such as Java, to allow class members to interact with each other. You’ll get used to it very quickly once you start writing object oriented PHP code, as it will likely be required for almost every method your class contains.

Of the other class methods, addHeader and addFooter are almost the same as before; however, notice that they no longer return values. Instead, they update the object’s $page member variable, which, as you’ll see, helps simplify the code that will use this class. We’ve also used the addContent method here; with this, we can add further content to the page (e.g. HTML that we’ve formatted ourselves, outside the object). Finally, we have the get method, which is the only method that returns a value. Once we’ve finished building the page, we’ll use this to create the HTML.

All these methods access the $page member variable, and this is no coincidence. The ability to tie PHP code (the methods) to the data (the variables) that it works on is the most fundamental feature of object oriented programming.

Here’s the class in action:

Example 2.5. 3.php (excerpt)

// Instantiate the Page class     $webPage = new Page();   

// Add the header to the page     $webPage->addHeader('A Page Built with an Object');   

// Add something to the body of the page     $webPage->addContent("<p> align="center">This page was " .       "generated using an object</p>n");   

// Add the footer to the page     $webPage->addFooter(date('Y'), 'Object Designs Inc.');   

// Display the page     echo $webPage->get();     ?>

To use the class, we’ve instantiated it with the new keyword. The object created from the class is placed in the $webPage variable. Through this variable, we have access to all the members of the object as we did with the $this variable above.

The first call to the addHeader method demonstrates the point:

$webPage->addHeader('A Page Built with an Object');

Only at the end, upon calling the get method, do we actually get anything back from the class. No longer do we need to worry about passing around a variable that contains the contents of the page – the class takes care of that.

Avoid output in classes

Instead of get, we could have endowed the Page class with a method called write to send the page code to the browser immediately. This would have made the code above slightly simpler, as the main script would not have had to get the code from the object and echo it itself. We avoided this for a reason.

It’s usually a bad idea to output directly from inside a class (with statements and functions such as echo and printf); doing so will reduce the flexibility of your classes. Allowing the value to be retrieved from the class gives you the option of performing additional transformations on it before you send it to the browser, or use it for some other purpose entirely (like putting it in an email!).

Notice also that the number of lines of code we have to write to use the class is fewer than were required in the earlier examples. Although it’s impossible to determine good application design by counting the number of lines of code, it is clear that the class has made the procedural code that uses it much simpler. From the point of view of people reading the code, it’s already fairly clear what’s going on, even without them having to look at the code for the Page class.

Understanding Scope

Write more than a few hundred lines of procedural PHP code and, no doubt, you’ll run into a parser error or, worse still, a mysterious bug caused by your accidentally having used a function or variable name more than once. When you’re including numerous files and your code grows increasingly complex, you may find yourself becoming more paranoid about this issue. How do you stop such naming conflicts from occurring? One approach that can help solve this problem is to take advantage of scope to hide variables and functions from code that doesn’t need them.

A scope is a context within which the variables or functions you define are isolated from other scopes. PHP has three available scopes: the global scope, the function scope, and the class scope. Functions and variables defined in any of these scopes are hidden from any other scope. The function and class scopes are local scopes, meaning that function X’s scope is hidden from function Y’s scope, and vice versa.

The big advantage of classes is that they let you define variables and the functions that use them together in one place, while keeping the functions hidden from unrelated code. This highlights one of the key theoretical points about the object oriented paradigm. The procedural paradigm places most emphasis on functions, variables being treated as little more than a place to store data between function calls. The object oriented paradigm shifts the emphasis to variables; the functions “back” the variables and are used to access or modify them.

Let’s explore this through an example:

<?php      // A global variable      $myVariable = 'Going global';    

// A function declared in the global scope      function myFunction()      {        // A variable in function scope        $myVariable = 'Very functional';      }    

// A class declared in the global scope      class MyClass {        // A variable declared in the class scope        var $myVariable = 'A class act';    

// A function declared in the class scope        function myFunction()        {          // A variable in the function (method) scope          $myVariable = 'Methodical';        }      }      ?>

In the above example, each of the $myVariable declarations is actually a separate variable. They can live together happily without interfering with each other, as each resides in a separate scope. Similarly, the two myFunction declarations are two separate functions, which exist in separate scopes. Thus PHP will keep all of their values separate for you.

Scope becomes important when you start to use object oriented programming in a significant way in your PHP applications. As many classes can have methods of the same name, you can design separate classes to deliver the same application programming interface (API). The scripts that use the classes can then use the same method calls, irrespective of which class was used to instantiate the object they’re working with. This can be a very powerful technique in writing maintainable code. We’ll look at this point more when we discuss polymorphism later in this chapter.

A Three Liner

Here’s how we could make the class even easier to use:

Example 2.6. 4.php (excerpt)

<?php      // Page class      class Page {    

// Declare a class member variable        var $page;        var $title;        var $year;        var $copyright;    

// The constructor function        function Page($title, $year, $copyright)        {          // Assign values to member variables          $this->page = '';          $this->title = $title;          $this->year = $year;          $this->copyright = $copyright;    

// Call the addHeader() method          $this->addHeader();        }    

// Generates the top of the page        function addHeader()        {          $this->page .= <<<EOD      <html>      <head>      <title>$this->title</title>      </head>      <body>      <h1 align="center">$this->title</h1>      EOD;        }    

// Adds some more text to the page        function addContent($content)        {          $this->page .= $content;        }    

// Generates the bottom of the page        function addFooter()        {          $this->page .= <<<EOD      <div align="center">&copy; $this->year $this->copyright</div>      </body>      </html>      EOD;        }    

// Gets the contents of the page        function get()        {          // Keep a copy of $page with no footer          $temp = $this->page;    

// Call the addFooter() method          $this->addFooter();    

// Restore $page for the next call to get          $page = $this->page;          $this->page = $temp;    

return $page;        }      }

This time, we’ve modified the constructor to accept all the variables needed for both the header and the footer of the page. Once the values are assigned to the object’s member variables, the constructor calls the addHeader method, which builds the header of the page automatically:

  // The constructor function        function Page($title, $year, $copyright)        {          // Assign values to member variables          $this->page = '';          $this->title = $title;          $this->year = $year;          $this->copyright = $copyright;    

// Call the addHeader() method          $this->addHeader();        }

As you can see, like member variables, methods can be called with the $this variable.

The addHeader method itself now fetches the data it needs from the member variables. For example:


We’ve also updated the get method so that it calls the addFooter method before returning the contents of the $page member variable. This means that when we come to fetch the finished page, the footer is added automatically.

  // Gets the contents of the page        function get()        {          // Keep a copy of $page with no footer          $temp = $this->page;    

// Call the addFooter() method          $this->addFooter();    

// Restore $page for the next call to get          $page = $this->page;          $this->page = $temp;    

return $page;        }

It took a little work to make sure we could call get more than once, without adding extra footers to the page, but this complexity is neatly hidden within the class.

Using the class externally is now even easier:

Example 2.7. 4.php (excerpt)

// Instantiate the page class       $webPage = new Page('As Easy as it Gets', date('Y'),         'Easy Systems Inc.');     

// Add something to the body of the page       $webPage->addContent(         "<p align="center">It's so easy to use!</p>n");     

// Display the page       echo $webPage->get();       ?>

Essentially, the page is now built using only three lines of code; I can also reuse this class to generate other pages. Represented as a UML diagram, the Page class is shown in Figure 2.1.

The PHP Anthology Volume 1, Chapter 2 - Object Oriented PHP

Figure 2.1. Page Class as UML

The member variables appear in the middle area, while methods appear in the bottom box. Also, the plus and minus signs are there to indicate to other developers which elements of the class are public (+) and which are private (-). Unlike languages such as Java, PHP does not enforce privacy on objects (enforced privacy constraints on class members will be added in PHP 5.0.); in the examples above, we could have accessed the $page member variable directly in our main script. Because we want the object to handle its own data without outside interference, we indicate in the UML diagram that only those members that have a + against them are available for public use. Those with a - are purely for internal use within the class.

That covers the basics of the class syntax in PHP, and should give you an idea of how classes compare with procedural code. With the syntax you’ve learnt, you should be able to write standalone classes containing the variables and functions you use frequently – a task that can really help tidy up your code and make it easier to maintain. This is a great start, but the real power of object oriented programming comes from using multiple objects and classes together. The rest of this chapter will look at some of the more advanced facets of the PHP object model, including references, inheritance, aggregation, and composition.

How do references work in PHP?

Most discussions of references in PHP begin with an opener like “references are confusing,” which may add to the myth that surrounds them. In fact, references are a very simple concept to grasp, yet they’re a concept that self-taught PHP developers only really need to consider once they begin writing object oriented applications. Until then, you’re probably oblivious to the way PHP handles variables behind the scenes. Much of the confusion that exists around references has more to do with developers who are experienced with other languages like C++ or Java trying to work with PHP: Java, in particular, handles object references in almost the opposite way to the approach PHP takes in version 4.

References vs. Pointers

Developers who are familiar with compiled languages such as C++ or Java should note that references in PHP are not analogous to pointers in other languages.

A pointer contains an address in memory that points to a variable, and must be dereferenced in order to retrieve the variable’s contents.

In PHP, all variable names are linked with values in memory automatically. Using a reference allows us to link two variable names to the same value in memory, as if the variable names were the same. You can then substitute one for the other.

What Are References?

To understand references, we have to begin by understanding how PHP handles variables under normal circumstances (i.e. without references).

By default, when a variable is passed to anything else, PHP creates a copy of that variable. When I say “passed,” I mean any of the following:

1. Passing a variable to another variable:

<?php         $color = 'blue';         $settings['color'] = $color;       ?>

$settings['color'] now contains a copy of $color.

2. Passing a variable as an argument to a function:

<?php       function isPrimaryColor($color)       {         // $color is a copy         switch ($color) {           case 'red':           case 'blue':           case 'green':             return true;             break;           default:             return false;         }       }     

$color = 'blue';       if (isPrimaryColor($color)) {         echo $color . ' is a primary color';       } else {         echo $color . ' is not a primary color';       }       ?>

When $color is passed to the function isPrimaryColor, PHP works with a copy of the original $color variable inside the function.

3. The same applies when passing variables to class methods:

<?php       class ColorFilter {         var $color;         function ColorFilter($color)         {           // $color is a copy           $this->color = $color;           // $this->color is a copy of a copy         }         function isPrimaryColor()         {           switch ($this->color) {             case 'red':             case 'blue':             case 'green':               return true;               break;             default:               return false;           }         }       }     

$color = 'blue';       $filter = new ColorFilter($color);       if ($filter->isPrimaryColor() ) {           echo ($color.' is a primary color');       } else {           echo ($color.' is not a primary color');       }       ?>

The original $color outside the class is passed to ColorFilter‘s constructor. The $color variable inside the constructor is a copy of the version that was passed to it. It’s then assigned to $this->color, which makes that version a copy of a copy.

All of these means of passing a variable create a copy of that variable’s value; this is called passing by value.

Using a Reference

To pass using a reference, you need to use the reference operator & (ampersand). For example:

<?php        $color = 'blue';        $settings['color'] = &$color;        ?>
$settings['color']/#rc#/ now contains a reference to the original $color variable.

Compare the following examples, the first using PHP's default copying behavior:

<?php        $color = 'blue';        $settings['color'] = $color; // Makes a copy        $color = 'red'; // $color changes        echo $settings['color']; // Displays "blue"        ?>
 The second involves passing by reference:
<?php        $color = 'blue';        $settings['color'] = &$color; // Makes a reference        $color = 'red'; // $color changes        echo $settings['color']; // Displays "red"        ?>
 Passing by reference allows us to keep the new variable "linked" to the original source variable. Changes to either the new variable or the old variable will be reflected in the value of both. So far, so good. You're probably wondering, "What's the big deal here? What difference does it make whether PHP copies or makes a reference to a variable, as long as we get what we expected?" For variables passed around a procedural program, you hardly ever need to worry about references. However, when it comes to objects interacting with one another, if you don't pass an object by reference, you may well get results you weren't expecting. The Importance of References Imagine you have a mechanism on your site that allows visitors to change the look and feel of the site - a user "control panel." It's likely that, to implement this sort of functionality, you'd have code that acts on a set of variables containing "look and feel" data, to modify them independently of the rest of the application's logic. Representing this simply with classes, first, let's see the class that will store data-related to look and feel: Example 2.8. 5.php (excerpt)
<?php        // Look and feel contains $color and $size        class LookAndFeel {          var $color;          var $size;          function LookAndFeel()          {            $this->color = 'white';            $this->size = 'medium';          }          function getColor()          {            return $this->color;          }          function getSize()          {            return $this->size;          }          function setColor($color)          {            $this->color = $color;          }          function setSize($size)          {            $this->size = $size;          }        }
 Next, we have a class that deals with rendering output: Example 2.9. 5.php (excerpt)
// Output deals with building content for display        class Output {          var $lookandfeel;          var $output;      

// Constructor takes LookAndFeel as its argument          function Output($lookandfeel)          {            $this->lookandfeel = $lookandfeel;          }          function buildOutput()          {            $this->output = 'Color is ' . $this->lookandfeel->getColor() .              ' and size is ' . $this->lookandfeel->getSize();          }          function display()          {            $this->buildOutput();            return $this->output;          }        }
 Notice the constructor for the Output class. It takes an instance of LookAndFeel as its argument so that, later, it can use this to help build the output for the page. We'll talk more about the ways classes interact with each other later in this chapter. Here's how we use the classes: Example 2.10. 5.php (excerpt)
// Create an instance of LookAndFeel        $lookandfeel = new LookAndFeel();      

// Pass it to an instance of Output        $output = new Output($lookandfeel);      

// Display the output        echo $output->display();        ?>
 This displays the following message:
Color is white and size is medium
 Now, let's say that, in response to one of the options on your user control panel, you want to make some changes to the look and feel of the site. Let's put this into action: Example 2.11. 6.php (excerpt)
$lookandfeel = new LookAndFeel(); // Create a LookAndFeel        $output = new Output($lookandfeel); // Pass it to an Output      

// Modify some settings        $lookandfeel->setColor('red');        $lookandfeel->setSize('large');      

// Display the output        echo $output->display();
 Using the setColor and setSize methods, we change the color to "red" and the size to "large," right? Well, in fact, no. The output display still says:
Color is white and size is medium
 Why is that? The problem is that we've only passed a copy of the LookAndFeel object to $output. So the changes we make to $lookandfeel have no effect on the copy that $output uses to generate the display. To fix this we have to modify the Output class so that it uses a reference to the LookAndFeel object it is given. We do this by altering the constructor: Example 2.12. 7.php (excerpt)
  function Output(&$lookandfeel)          {            $this->lookandfeel = &$lookandfeel;          }
 Notice that we have to use the reference operation twice here. This is because the variable is being passed twice - first to the constructor function, then again, to place it in a member variable. Once we've made these changes, the display looks like this:
Color is red and size is large
 In summary, passing by reference keeps the target variable "linked" to the source variable, so that if one changes, so does the other. 
   Good and Bad Practices When working with classes and objects, it's a good idea to use references whenever an object is involved. Occasionally, you may have to do the same with an array, such as when you want to sort the array in a different section of code. But, for the most part, normal variables will not need this treatment, simply because, when your code reaches the level of complexity where you'd need to do so, you will (I hope!) be storing variables inside objects and passing the complete object by reference. Let's look at some other situations in which you might need to use references...

// Make sure $myObject is a reference to         // the variable created by the new keyword         $myObject = &new MyClass();
 This looks odd at first, but remember, a variable created by the new keyword is being passed here - even if you can't see it. The reference operator saves PHP from having to create a copy of the newly-created object to store in $myObject.
class Bar {         }       

class Foo {           // Return by reference           function &getBar()           {             return new Bar();           }         }       

// Instantiate Foo         $foo = &new Foo();       

// Get an instance of Bar from Foo         $bar = &$foo->getBar();
 In the above example, you'll notice the getBar method in the Foo class. By preceding the function name with the reference operator, the value the function returns is passed by reference. Note that we also had to use a reference operator when assigning the return value of getBar to $bar. This technique is commonly used when a class method will return objects. What's bad practice is the following:
function display($message) {           echo $message;         }       

$myMessage = 'Hello World!';       

// Call time pass by reference - bad practice!         display(&$message);
 That's known as a call-time pass-by-reference, which PHP controls with the following setting in php.ini:
allow_call_time_pass_reference = Off
 By default, in recent PHP releases the above setting should be switched to Off; turning it on is "frowned upon" by PHP's makers. Switched off, PHP will generate warning errors every time a function call specifies an argument should be passed by reference. As such, it's good practice to leave this setting off. The reason why call time pass by reference is a "bad thing" is that call time passing by reference can make code extremely difficult to follow. I've occasionally seen PHP XML parsers written using a call-time pass-by-reference - it's nearly impossible to gain any idea of what's going on. The "decision" as to whether a variable is passed by reference or not is one that belongs to the function being called, not the code that calls it. The above code written correctly would look like this:
// Accept by reference - good practice         function display(&$message)         {           echo $message;         }       

$myMessage = 'Hello World!';       

 Performance Issues Depending on the scale of your application, there are some performance issues you might need to consider when using references. In simple cases of copying one variable to another PHP's internal reference counting feature prevents unnecessary memory usage. For example,
$a = 'the quick brown fox';         $b = $a;
 In the above example, the value of $b would not take up any extra memory, as PHP's internal reference counting will implicitly reference $b and $a to the same location in memory, until their values become different. This is an internal feature of PHP and affects performance without affecting behavior. We don't need to worry about it much. In some cases, however, using a reference is faster, especially with large arrays and objects, where PHP's internal reference counting can't be used. and the contents must therefore be copied. So, for best performance, you should do the following:
  • With simple values such as integers and strings, avoid references whenever possible.
  • With complex values such as arrays and objects, use references whenever possible.
  References and PHP 5 With PHP 5, references will cease to be an issue because the default behavior of PHP, when passing objects, will be to pass by reference. If you ever need a copy of an object, you can use the special __clone method to create copies. Essentially, the change brings PHP in line with the majority of object oriented programming languages like Java, and will certainly do a lot to reduce the confusion surrounding the subject. For now, though, and until PHP 5 has been widely adopted, knowing how references work is important. 
  How do I take advantage of inheritance? Inheritance is one of the fundamental pieces of the object oriented paradigm and is an important part of its power. Inheritance is a relationship between different classes in which one class is defined as being a child or subclass of another. The child inherits the methods and member variables defined in the parent class, allowing it to "add value" to the parent. The easiest way to see how inheritance works in PHP is by example. Let's say we have this simple class:
 Example 2.13. 8.php (excerpt)
<?php          class Hello {            function sayHello()            {              return 'Hello World!';            }          }
 Using the extends keyword, we can make a class that's a child of Hello: Example 2.14. 8.php (excerpt)
class Goodbye extends Hello {            function sayGoodbye()            {              return 'Goodbye World!';            }          }

Goodbye is now a child of Hello. Expressed the other way around, Hello is the parent or superclass of Goodbye. Now, we can simply instantiate the child class and have access to the sayHello and the sayGoodbye methods using a single object:    Example 2.15. 8.php (excerpt)
$msg = &new Goodbye();        

echo $msg->sayHello() . '<br />';          echo $msg->sayGoodbye() . '<br />';          ?>
 That example shows the basics of how inheritance works, but doesn't demonstrate its real power... This comes with the addition of overriding. Overriding What happens when we give a function in the child the same name as a function in the parent? An example: Example 2.16. 9.php (excerpt)
<?php          class Hello {            function getMessage()            {              return 'Hello World!';            }          }        

class Goodbye extends Hello {            function getMessage()            {              return 'Goodbye World!';            }          }
 Both classes have the same method name, getMethod. This is perfectly acceptable to PHP - it makes no complaints about a method being declared twice. Here's what happens when we use the classes: Example 2.17. 9.php (excerpt)
$hello = &new Hello();          echo $hello->getMessage() . '<br />';        

$goodbye = &new Goodbye();          echo $goodbye->getMessage() . '<br />';          ?>
 And the output is as follows:
Hello World!          Goodbye World!
 Calling getMessage via the $goodbye object displays "Goodbye World!" The method in the child class is overrides the method in the parent class. You can also have the child class make use of the parent class's method internally, while overriding it. For example: Example 2.18. 10.php
<?php          class Hello {            function getMessage()            {              return 'Hello World!';            }          }        

class Goodbye extends Hello {            function getMessage()            {              $parentMsg = parent::getMessage();              return $parentMsg . '<br />Goodbye World!';            }          }        

$goodbye = &new Goodbye();          echo $goodbye->getMessage() .'<br />';          ?>
 Using the parent keyword, we can call the parent class's method. Note that we can also call the parent class by name to achieve exactly the same result:
class Goodbye extends Hello {            function getMessage() {              $parentMsg = Hello::getMessage();              return $parentMsg . '<br />Goodbye World!';            }          }
 Notice that we've replaced the parent keyword with the name of the Hello class. The output is exactly the same. Using parent, however, saves you from having to remember the name of the parent class while working in the child, and is the recommended syntax. A call such as parent::getMessage() or Hello::getMessage() from a non-static method is not the same as calling a static function. This is a special case where inheritance is concerned. The called function in the parent class retains access to the instance data, and is therefore not static. This may be demonstrated as follows: Example 2.19. 11.php
<?php          class A {              var $a = 1;              function printA()              {                  echo $this->a;              }          }        

class B extends A {              var $a = 2;              function printA()              {                 parent::printA();                 echo "nWasn't that great?";              }          }        

$b = new B();          $b->printA();          ?>
 The output generated from the above is as follows:
 Wasn't that great? PHP does not cascade constructors

Most object oriented languages, like Java, will run the constructor of the parent class automatically, before running an overriding constructor in the child class. This is called cascading constructors - it's a feature that PHP does not have.

If you create a constructor in a child class, be aware that you are completely overriding the parent class's constructor, and that you must call it explicitly from your new constructor if you still want the parent class to handle its share of the object initialization. Overriding declared member variables is achieved in exactly the same way as methods, although you're unlikely to use this feature frequently. 
  Inheritance in Action Now that you have a rough idea of how inheritance is used in PHP, it's time to look at an example that should give you a better idea of how inheritance can be applied. The following example implements a simple navigation system for a Web page, generating the HTML that appears at the top of the page. By having one class inherit from another, it becomes possible to add "crumb trail" navigation to the page when it's needed. First up, the StandardHeader class deals with generating the HTML for the top of the page, as well as supplying the setHeader and getHeader methods to access the variable where the HTML is stored. Example 2.20. 12.php (excerpt)
<?php           /**            * A standard header for a Web page            */           class StandardHeader {             /**              * The header HTML is stored here              */             var $header = '';         

/**              * The constructor, taking the name of the page              */             function StandardHeader($title)             {               $html = <<<EOD           <html>           <head>           <title> $title </title>           </head>           <body>           <h1>$title</h1>           EOD;               $this->setHeader($html);             }         

/**              * General method for adding to the header              */             function setHeader($string)             {               if (!empty($this->header)) {                 $this->header .= $string;               } else {                 $this->header = $string;               }             }         

/**              * Fetch the header              */             function getHeader()             {               return $this->header;             }           }
 Now, the subclass CategoryHeader brings extra functionality to its parent, adding the "bread crumb" links to the HTML that was generated. We don't need to recreate the setHeader and getHeader methods, as these are inherited from StandardHeader when CategoryHeader is instantiated. Example 2.21. 12.php (excerpt)
/**            * Subclass for dealing with Categories, building a breadcrumb            * menu            */           class CategoryHeader extends StandardHeader {             /**              * Constructor, taking the category name and the pages base URL              */             function CategoryHeader($category, $baseUrl)             {               // Call the parent constructor               parent::StandardHeader($category);         

// Build the breadcrumbs               $html = <<<EOD           <p><a href="$baseUrl">Home</a> >           <a href="$baseUrl?category=$category">$category</a></p>           EOD;               // Call the parent setHeader() method               $this->setHeader($html);             }           }
 Let's now put these two classes to use:
Example 2.22. 12.php (excerpt)         

// Set the base URL           $baseUrl = '12.php';         

// An array of valid categories           $categories = array('PHP', 'MySQL', 'CSS');         

// Check to see if we're viewing a valid category           if (isset($_GET['category']) &&               in_array($_GET['category'], $categories)) {         

// Instantiate the subclass             $header = new CategoryHeader($_GET['category'], $baseUrl);           } else {         

// Otherwise it's the home page. Instantiate the Parent class             $header = new StandardHeader('Home');           }         

// Display the header           echo $header->getHeader();           ?>           <h2>Categories</h2>           <p><a href="<?php echo $baseUrl; ?>?category=PHP">PHP</a></p>           <p><a href="<?php echo $baseUrl; ?>?category=MySQL">MySQL</a></p>           <p><a href="<?php echo $baseUrl; ?>?category=CSS">CSS</a></p>           </body>           </html>

 As you can see, the controlling logic above looks for a $_GET['category'] variable. If it exists, it creates an instance of CategoryHeader, displaying the navigation to allow users to find their way back to the home page. But if it doesn't exist, it creates an instance of the parent StandardHeader instead, which applies when users view the home page (and therefore does not require bread crumbs to find their way back). In other words, inheritance allows us to add the extra functionality we need without having to reproduce the logic that already resides within the parent class; the existing methods and logic can be reused via the child subclass. Inheritance provides a powerful mechanism to make classes that are modular, addressing a specific problem, while still making available shared methods and variables that can be used irrespective of the specific object we're dealing with. Avoid Deep Inheritance Structures

As a general rule of thumb, when using inheritance to build class hierarchies, avoid going deeper than two generations.

Doing so is often a sign of a bad design, in which opportunities for classes to interact in different ways (see the next solution) were missed. In practice, having more than two generations of classes often leads to all sorts of debugging problems and makes the code difficult to maintain. For example, it can become hard to keep track of variable names you've used higher up in the hierarchy.  
  How do objects interact? Aside from inheritance, there are other ways for objects to interact; for example, one object uses another object. In many ways, such interactions are more important than inheritance, and this is where the object oriented paradigm shows its real power. There are two ways in which one object can use another: aggregation and composition.
 Aggregation Aggregation occurs when one object is given another object on "temporary loan." The second object will usually be passed to the first through one of the first's member functions. The first object is then able to call methods in the second, allowing it to use the functionality stored in the second object for its own purposes. A common example of aggregation in action involves a database connection class. Imagine you pass a database connection class to some other class, which then uses the database connection class to perform a query. The class performing the query aggregates the database connection class. Here's a simple example using the MySQL class, which we'll create in Chapter 3, PHP and MySQL: Example 2.23. 13.php
<?php            // Include the MySQL database connection class            require_once 'Database/MySQL.php';          

// A class which aggregates the MySQL class            class Articles {              var $db;              var $result;              // Accept an instance of the MySQL class              function Articles(&$db)              {                // Assign the object to a local member variable                $this->db = &$db;                $this->readArticles();              }              function readArticles()              {                // Perform a query using the MySQL class                $sql = "SELECT * FROM articles LIMIT 0,5";                $this->result = &$this->db->query($sql);              }              function fetch()              {                return $this->result->fetch();              }            }          

// Create an instance of the MySQL class            $db = &new MySQL('localhost', 'harryf', 'secret', 'sitepoint');          

// Create an instance of the Article class, passing it the MySQL            // object            $articles = &new Articles($db);          

while ($row = $articles->fetch()) {              echo '<pre>';              print_r($row);              echo '</pre>';            }            ?>
 In the above example, we instantiate the MySQL class outside the Articles class, then pass it to the Articles constructor as Articles is instantiated. Articles is then able to use the MySQL object to perform a specific query. In this case, Articles aggregates the MySQL object. Figure 2.2 illustrates this relationship with UML. The PHP Anthology Volume 1, Chapter 2 - Object Oriented PHP
Figure 2.2. Aggregation Composition Composition occurs when one object "completely owns" another object. That is, the first object was responsible for creating (instantiating) the second object. There are many cases in which this can be useful, although, typically, composition is used when it's likely that the first object will be the only one that needs to use the second object. One example from Chapter 1, Access Control is the Auth class, which composes an instance of the Session class, creating it in the constructor:
class Auth {              ...          

/**               * Instance of Session class               * @var Session               */              var $session;          


function Auth (&$dbConn, $redirect, $md5 = true)              {                $this->dbConn = &$dbConn;                $this->redirect = $redirect;                $this->md5 = $md5;                $this->session = &new Session();                $this->checkAddress();                $this->login();              }
 Because the Auth class needs to read and write to session variables, and only a limited number of other, unrelated classes in an application are likely also to need to use Session, it's logical that it gets to create its own Session object. Figure 2.3 illustrates the composition in this example with UML. The PHP Anthology Volume 1, Chapter 2 - Object Oriented PHP
Figure 2.3. Composition
  Spotting the Difference The general "thought test" to spot whether object A aggregates or composes object B is to ask, "What happens if object A dies? Will object B still be alive?" If object B outlives the death of object A, object A is said to aggregate object B. But if object B dies when object A dies, then object A is said to compose object B. In terms of practical development, knowing when to apply aggregation or composition is important.
 Aggregation has the advantage of lower overhead, because a single object will be shared by many other objects. Certainly, aggregating your database connection class is a good idea; composing it with every object that wants to make a query may require you to have multiple connections to your database, which will quickly halt your application when your site attracts high levels of traffic. Composition has the advantage of making classes easier to work with from the outside. The code that uses the class doesn't have to worry about passing it the other objects it needs, which, in a complex application, can often become tricky and result in a design "work around." Composition also has the advantage that you know exactly which class has access to the composed object. With aggregation, another object sharing the aggregated object may do something to its state that "breaks" the object as far as the other classes that use it are concerned. Polymorphism Another powerful aspect of object oriented programming is polymorphism - the ability of different classes to share an interface. An interface is one or more methods that let you use a class for a particular purpose. For example, you could have two database connection classes - one for MySQL and one for PostgreSQL. As long as they both offered a query method, you could use them interchangeably for running queries on different databases. The query method is a simple interface that the two classes share. The classes sharing the same interface are often inherited from a parent class that makes the common methods available. Again, this is best understood by example. First, we define an abstract base class, Message, which provides the common method getMessage. Beneath the Message class, we define concrete classes, each of which creates a specific message. The terms "abstract" and "concrete" refer to class usage, in particular, whether a class is intended to be used directly or not. An abstract class is one in which some functionality or structure is to be shared by all subclasses, but is not intended to be used directly; typically, it has one or more empty methods that don't do anything useful. In other words, you're not supposed to create objects from an abstract class. A concrete class is a subclass of the abstract class from which you can create objects. Some languages, like Java, provide support for abstract classes within the language syntax - something PHP 4 doesn't offer. You can still use the concept of abstract classes when designing applications, though you might consider adding documentation to tell other developers working with the code that the class is abstract. Example 2.24. 14.php (excerpt)
<?php             class Message {               var $message;               function setMessage($message)               {                 $this->message = $message;               }               function getMessage()               {                 return $this->message;               }             }             class PoliteMessage extends Message {               function PoliteMessage()               {                 $this->setMessage('How are you today?');               }             }           

class TerseMessage extends Message {               function TerseMessage()               {                 $this->setMessage('Howzit?');               }             }           

class RudeMessage extends Message {               function RudeMessage()               {                 $this->setMessage('You look like *%&* today!');               }             }
 Now, we define the MessageReader class, which takes an array of Message objects through its constructor. Example 2.25. 14.php (excerpt)
class MessageReader {               var $messages;               function MessageReader(&$messages) {                 $this->messages = &$messages;                 $this->readMessages();               }               function readMessages() {                 foreach ($this->messages as $message) {                   echo $message->getMessage() . '<br />';                 }               }             }
 The important thing to note here is that, as far as MessageReader is concerned, a "Message object" is any object that was instantiated from the Message class or one of its subclasses. Did you see how, inside the readMessages method, we call the getMessage method? This code will work on any object that has a getMessage method - including any subclass of Message. Now, to prove the point, let's create some Message objects using our three subclasses at random: Example 2.26. 14.php (excerpt)
$classNames =               array('PoliteMessage', 'TerseMessage', 'RudeMessage');             $messages = array();             srand((float)microtime() * 1000000); // Prepares random shuffle             for ($i = 0; $i < 10; $i++) {               shuffle($classNames);               $messages[] = new $classNames[0]();             }             $messageReader = new MessageReader($messages);             ?>
 By creating the array $classNames and then repeatedly shuffling it, we can take the first element of the array and use it to create a new object:
  $messages[] = new $classNames[0]();
 This is an example of a variable function. The expression $classNames[0] is evaluated to determine the name of the constructor (PoliteMessage, TerseMessage, or RudeMessage) to call. Finally, the $messages array contains ten messages, randomly selected, and is passed to the constructor of MessageReader on instantiation. Here's a sample result:
You look like *%&* today!             Howzit?             How are you today?             How are you today?             How are you today?             You look like *%&* today!             How are you today?             How are you today?             Howzit?             How are you today?
 Each time we execute the script, the list is different. Because all the concrete message classes share the same getMethod function (i.e. they implement the same interface), the MessageReader class is able to extract the data without knowing which particular type of message it's dealing with. The ability for a group of related classes to work interchangeably is called polymorphism, and is illustrated in the UML diagram in Figure 2.4. The PHP Anthology Volume 1, Chapter 2 - Object Oriented PHP
Figure 2.4. Polymorphism This aspect of object oriented programming can be very powerful once you realize its worth. You might have a collection of objects representing HTML tags, for example, each being a subclass of a parent HTMLTag class, from which they all inherit a render method. Another class that handles the rendering of a page could take a collection of HTMLTag objects and create the page by calling each object's render method. Further Reading
  Look out for more chapters from The PHP Anthology on SitePoint in coming weeks! If you can't wait, download the sample chapters, or order your very own copy now!


Category: programming Time: 2004-01-05 Views: 3

Related post

iOS development

Android development

Python development

JAVA development

Development language

PHP development

Ruby development


Front-end development


development tools

Open Platform

Javascript development

.NET development

cloud computing


Copyright (C), All Rights Reserved.

processed in 0.114 (s). 12 q(s)