What was introduced in PHP 5

PHP 5 introduced a number of revolutionary features to the language that made it a much more elegant solution to many of the common programming challenges developers face. Object support went from something of a glorified after-thought to a truly compelling, modern approach. Several useful libraries and interfaces were added, and exception handling was finally given the attention many developers had longed for. Each of these are covered in their own chapters, but there were just a few other add-ons that, while too important not to cover, didn’t easily fit into more focused chapters.

Briefly, we’re going to look at three of these new features: type-hinting, objects being passed by reference, and indirect referencing.

Type hinting allows you to more precisely specify the types of arguments that should be passed into your function. In the definition, you can do something like:

function myFunction(MyClass $object) {
//do something with $object
}

This sets up a guarantee that when the function is run, $object will either be an instance of “MyClass”, an instance of a child class of MyClass type, or an instance of a class that implements an interface called MyClass. And this might be really important. Having it specified this way in the function definition will also ensure that anyone working on your code later will know that. In addition to class and interface names, you can also type-hint for arrays. The ‘null’ value is always allowed as a default:

function myFunction(MyClass $object = null) {
//if no argument is passed, or if a null is passed explicitly, this function will work
}

But you cannot have something like this:

function myFunction(MyClass $object = new MyClass()) {
//this code will not parse
}

Oddly enough though, you CAN do this:

function myFunction(array $array = array()) {
//this code is perfectly legit
}

And you cannot type-hint for scalars, like ‘int’, ‘float’, or ‘string’:

function myFunction(int $int) {
//won’t work in PHP 5 – maybe PHP 6 will allow?
}

However, there is one warning to bear in mind with this approach. If the argument is NOT an instance of MyClass (or a child, or an implementer) your script will trigger a catchable fatal error, not an exception. In order to deal with this type of fatal error, you need to create a global-scope function and use it as the argument in a call to ‘set_error_handler()’ to replace PHP’s default handler. We’ll take a closer look at creating custom error handlers in another video, but here’s some code we could use in this situation:

{@todo – write and test example error-handler code}

However, if you’d rather not deal with custom error handlers, there are other ways to ensure that your function is getting the variable type you expect, and still make it clear to those who follow what is expected. There is a special docblock comment tagline “@param”. If you use a development environment such as Zend Studio, or run phpDocumentor on your code, the argument requirement will be listed along with the function documentation. And if you want to halt execution when the wrong argument type is passed, you can test the type explicitly within your function and throw an exception that can be caught and handled properly. Here’s what that looks like in practice:

/**
* this function does something useful
* @param MyClass $object
*/
function myFunction($object) {
if(! $object instanceof MyClass) {
throw new InvalidArgumentException(‘$object must be an instance of MyClass’);
}
//do something
}

We’ll look more at docblock comments as well as phpDocumentor in another video. But suffice to say this approach will work in many of the situations when you might consider using type-hinting, and it can be made to work with multiple types and scalars. The disadvantage, of course, is somewhat longer code, and needing to ensure that your function is called within the scope of a matching try-catch block.

The “instanceof” keyword, by the way, is also new to PHP 5. It’s essentially an analog to the is_a() function that’s been around since PHP 4. Like type-hinting, it tests whether an object is an instance of, a child of, or an implementation of the class or interface name in the right-hand argument.

For a while, the PHP engineers had decided to deprecate “is_a()” in favor of the instanceof keyword, and in PHP 5 before 5.3, it would toss an E_STRICT warning. However, as of PHP 5.3 it is no longer deprecated. Both is_a() and instanceof are now considered equally valid.

Perhaps the most significant change between PHP 4 and 5 is the fact that objects are now passed by reference by default. The reason I say it’s the most significant isn’t because it completely revolutionizes the language – PHP 4 could pass objects by reference by using the ‘&’ in front of variables in a function definition, as in the example shown here:

function myFunction(&$obj) {
//In PHP 4, $obj is a reference to an object, rather than a copy of it
}

The reason it’s so significant is because, while the PHP engineers worked very hard to make sure almost all PHP 4 scripts would work the same under PHP 5, this is one area where they might not. Consider the following code:

class Account {
var $balance = 0;

static function addFunds($account, $amount) {
$account->balance += $amount;
}
}

$account = new Account();
Account::addFunds($account, 20);
echo $account->balance;

In PHP 5, the output will be ’20’, but in PHP 4, no change actually takes place to the $account object, so the output is ‘0’. Under PHP 4, the function gets a copy of the $account variable, rather than a reference to the original variable as it does in PHP 5. And in this example, obviously it’s the PHP 5 behavior that would be intended. But that’s not always the case.

Imagine that a PHP 4 script were written that takes an object and performs some action on it with the expectation that it NOT change the original object. Trying to run that same script in PHP 5 could result in very unexpected behavior. And indeed, if your old scripts break when running under PHP 5, there’s a good chance that this new behavior is behind it.

Now, because there are some situations where you want the ability to work on a copy of an object rather than the object itself, PHP 5 provides an easy mechanism for doing that.

$object = new MyClass(5, 5);
$copyOfObject = clone $object;

In this case, any properties set in $object will be set identically in $copyOfObject, so making changes to $copyOfObject won’t affect $object. In another video we look at how you can have more fine-grained control over exactly how an object is copied by defining the __clone() method in your class, but for most cases, the default behavior of ‘clone’ is sufficient.

The final addition to PHP 5 we’re going to look at is called “indirect referencing”. And it’s a great way to take many lines of code and turn them into just a few. Consider this example from a typical PHP 4 script:

$var1 = $object->var1;
$var2 = $var1->var2;

var1 is actually an object itself that also happens to be a property on $object, and var2 is a property of var1. In PHP 5 we can shorten this to just:

$var2 = $object->var1->var2;

In PHP 5, there is no need to actually declare temporary variables in these types of situations. The code above will simply get the first variable and then use it to get the subsequent variable. It works for functions and methods as well:

$var2 = $object->method1()->var2;
$var2 = myFunction()->var2;
$var8 = $object->var1->method2()->var3->method4()->method5()->var6->var7->var8;
//so long as an object is returned with each ‘get’ or method call (aside from the last), all these examples are valid!

Indirect referencing leads to a handy programming technique called “chaining”. The last example shows how it can drastically shorten code versus PHP 4.

There were a number of other important changes introduced in PHP 5, and several of those will be examined in the section on Object Oriented Programming, but this concludes the ones I wanted to look at here.

October 14 2009 10:24 pm | introduction and PHP tutorial scripts

Comments are closed.