PHP Anthology, Volume 1, Chapter 2. Object Oriented PHP | 5

PHP Anthology, Volume 1, Chapter 2. Object Oriented PHP

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:

Next, we have a class that deals with rendering 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:

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:

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:

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.

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!';
display($message);

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.

The easiest way to see how inheritance works in PHP is by example. Let’s say we have this simple class:

Using the extends keyword, we can make a class that’s a child of Hello:

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:

That example shows the basics of how inheritance works, but doesn’t demonstrate its real power… This comes with the addition of overriding.

Created: March 27 2003
Revised: January 2, 2004

URL: http://webreference.com/programming/phpanth2