Introduction
A couple of months ago the long awaited version 5.0 of the PHP language was released. It took a while but it has definitely been worth the wait. In this article I will summarize the new exciting features PHP5 has to offer.
Zend Engine version 2.0
Zend is the company behind PHP. They offer all kinds of interesting add-on products as well as support and certification in the field of PHP but their most important assed is the contribution they offer to the Open Source world: the Zend Engine 2.0. This engine is the core of PHP. The whole OO model has been revamped and extended as well as numerous other additions and enhancements.
Private members
Back in the PHP4 days, class members were always 'public'. They weren't really called that way but effectively they were. One could read and manipulate them from anywhere in the code and there was no protection or whatsoever to prevent this from happpening. Of course good coders would never do this but it's a lot better if we can enforce variable protection in our very model.
Let's look at the following simple piece of code:
Class clsDemo {
private $m_sText = "Hello World!";
function getText() {
return $this->m_sText;
}
function setText($p_sText) {
$this->m_sText = $p_sText;
}
}
$objDemo = new clsDemo();
echo $objDemo->printText();
echo $objDemo->m_sText;
In the PHP4 days a good coder would of course only access the member $m_sText with the defined access methods in the example. However, it worked perfectly fine to alter the member by simply assigning a new value to $objDemo->m_sText. In this PHP5 example this is impossible. Accessing the value in any other way than through the getText and setText method will result in an error:
PHP Fatal error: Cannot access private property clsDemo::$m_sText
As you can see we can now effectively prevent members defined for internal use inside the object only from being accessed from outside the object!
Protected members
Further enriching the object model and offering various ways to organize our projects the 2.0 engine also features so called protected members. These members can be accessed both from inside the object but also from classes that extend the class that has the protected member:
Class clsDemo {
protected $m_sText = "Hello";
private $m_sPrivate = "This is a secret";
function printPrivate() {
return $this->m_sPrivate;
}
}
Class clsDemoChild extends clsDemo {
function printVars() {
echo $this->m_sText."\n";
echo $this->m_sPrivate;
echo clsDemo::printPrivate()."\n";
}
}
$objDemo = new clsDemoChild();
echo $objDemo->printVars();
echo $objDemo->m_sText;
In the above example some interesting things will occur. The first line of the printVars() method will actually print 'Hello'. The protected member is interited from the parent class. The second line however tries to access the private member. This won't print anything because the private member is NOT inherited by the extending class. If you have notices enabled you will get:
PHP Notice: Undefined property: clsDemoChild::$m_sPrivate
We can however still access it by calling the printPrivate() method from the parent class as you can see in the third line of the printVars() method.
The line that tries to access the protected member $m_sText from outside the proper context will throw an error because we cannot access protected members this way.
Private methods
We've now seen that we can declare members private or protected to enhance encapsulation and protect the integrity of our object model. But the story doesn't end here. We can do the same thing with methods! A private method can only be called from code defined within the same class.
Class clsDemo {
private function privateMethod() {
return "private method called!\n";
}
function publicMethod() {
return $this->privateMethod();
}
}
$objDemo = new clsDemo();
echo $objDemo->publicMethod(); // SUCCEEDS
echo $objDemo->privateMethod(); // FAILS
In the above example we have defined a simple class with a private and a public method. The public method calls the private method. This is a call from within the object itself which is why it will perfectly print out 'private method called!'. When we try to call the private method directly PHP5 will throw a fatal error:
PHP Fatal error: Call to private method clsDemo::privateMethod() from context ''
We cannot call private methods from anywhere outside the object itself.
Now let's extend our little class a bit:
Class clsExtend extends clsDemo {
function printOut() {
return $this->privateMethod();
// FAILS when called
}
function printOut2() {
return clsDemo::privateMethod();
// FAILS when called
}
function printOut3() {
return $this->publicMethod();
// prints out the text as expected
}
}
We've now created a child class with three methods. Two of them will throw errors when called. The first method will fail because we are calling a private method from the parent class from within an extending class. Since the extending class is not the original class this will not work. We get:
PHP Fatal error: Call to private method clsDemo::privateMethod() from context 'clsExtend'
The second method tries to call the private method directly. This will also fail because this too is a call from outside the original class. We get the same error.
The last method is correct. We access the private method by calling it from within the proper context!
Protected methods
A protected method can only be called from code within the original class like with private methods, but also from code in classes that extend the one the protected method was defined in:
Class clsDemo {
protected function protectedMethod() {
return "protected method was called";
}
}
Class clsExtends extends clsDemo {
function printOut() {
return $this->protectedMethod();
}
}
$objDemo = new clsExtends();
echo $objDemo->printOut();
$objDemo2 = new clsDemo();
echo $objDemo2->protectedMethod();
The class will probably speak for itself. When we call the printOut() method of the extending class we will see the output without any problem. However when trying to call protectedMethod() from the outside like we are doing in the last line of this example, PHP will throw an error:
PHP Fatal error: Call to protected method clsDemo::protectedMethod() from context ''
Private and protected members and methods were a long awaited feature for PHP. It brings PHP a lot closer to languages like JAVA and the UML modeling language. But this isn't everything, not even by far!
Abstract classes
PHP5 introduces the possibility of defining abstract classes. An abstract class can be seen as a class which is only partially implemented. Some of the methods contain code but it also contains methods which don't. The methods without any code are also declared 'abstract'. We cannot instantiate an abstract class. The only way to create an actual object with the methods and properties defined in the abstract class is to write an extending class which implements the methods which are empty. Even when all the methods in an abstract class contain code we can still NOT instantiate it. Declaring classes abstract forces the developer to write at least one extending class.
An example:
abstract Class clsFrame {
abstract public function sayHi();
}
Class clsImplemented extends clsFrame {
public function sayHi() {
return "Hi there!";
}
}
$objTest = new clsImplemented();
echo $objTest->sayHi();
In the example we see an abstract class with one abstract method. The code example will print 'Hi there!'; If we were to instantiate an object from clsFrame we would get the following error:
PHP Fatal error: Cannot instantiate abstract class clsFrame
To summarize:
- Abstract classes can NOT be instantiated, whether they contain abstract methods or not
- Abstract methods are methods which are defined but without code in it. Attempting to declare a method abstract but yet writing code in it will result in an error
Interfaces
Another concept enhancing the object model even further are interfaces. An interface can be seen as a list of method definitions without any code inside them.
interface itfDemo {
public function sayHi();
public function sayBye();
}
The above example is a simple greeting interface. Two methods are defined. We can now write classes which implement the interface:
Class clsDemo implements itfDemo {
public function sayHi() {
return "Hi!";
}
public function sayBye() {
return "Bye!";
}
}
If we choose to write a class that implements a certain interface, we HAVE to create all methods defined in the interface in order to be able to have a class from which we can instantiate objects. However we can still write classes only partially implementing the interface if we declare them abstract. We have to implement the rest of the interface in an extending class.
It's also noteworthy that a class may implement an unlimited number of interfaces.
With the help of abstract classes and interfaces PHP5 further enriches the object model enabling us to implement a much more fine-tuned application design.
Unified constructors and: destructors!
In PHP4 we were used to constructors bearing the same name as the class they were defined in. In PHP5 the constructor always gets the same name. In addition to that, the new concept of destructors has been introduced. As we know, a constructor is called automatically when an object is instantiated. A destructor follows the same pattern: It's called whenever an object is destroyed. Explicitly destroying an object is also something we couldn't do in PHP4.
Class clsDemo {
function __construct() {
echo "hello world!";
}
function __destruct() {
echo "goodbye cruel world!";
}
}
As you see in the above example the constructor is now called __construct() and we have an additional option of adding a __destruct() method. If we choose to get rid of an object by calling unlink($objMyObject) the destructor will be called immediately. With this we get the option of doing all kinds of 'cleanup routines' before objects disappear from the scene. If we don't unset the object the destructor will still be called when script execution finishes.
Exception handling
A concept well known by anyone who programs JAVA but completely new for PHP is exception handling. Exception handling enables us to gracefully handle errors and take appropriate action in our code when various errors occur. PHP5 introduces the built in exception class. It has the following methods:
- __construct() constructor (arguments: errorstring, optional integer error code)
- getMessage() returns the error string as described in the constructor
- getCode() returns the optional error code
- getFile() path to the php file in which the exception was generated
- getLine() line number in which the exception was generated
- getTrace() array containing stack-trace information about the exception
- getTraceAsString() same as getTrace() but as a string
$nValue = -1;
if($nValue < 0) {
throw new exception ("value below 0");
}
PHP will generate the following error information either in output or in the error log depending on our configuration. Also, execution will not proceed but halt immediately.
Fatal error: Uncaught exception 'Exception' with message 'value below 0'
in /var/www/demo/demo.php:4
Stack trace:
#0 {main}
thrown in /var/www/demo/demo.php on line 4
Stack trace:
#0 {main}
thrown in /var/www/demo/demo.php on line 4
This message already indicates what we will see next: we can actually catch exceptions!
class clsCouldGoWrong {
function __construct($nArg) {
if($nArg < 0) throw new exception("value
below 0");
echo "We're still alive!";
}
}
try {
$objCouldGoWrong = new clsCouldGoWrong(-1);
}
catch (Exception $e) {
echo "things went bonkers, the error code
was: ".$e->getMessage();
}
As you can see in the code example we can actually 'try' things and if it doesn't work out the way we expected we can anticipate and take action. Whenever an exception is thrown inside a 'try' block code after the exception was thrown will not be executed anymore. Instead execution will continue in the 'catch' block. This means that in our example the message 'We're still alive!' is never outputted. We can make our error-handling even more sophisticated by taking care of different error types that may occur:
class belowZeroException extends Exception {};
class aboveNineException extends Exception {};
class clsCouldGoWrong {
function __construct($nArg) {
if($nArg < 0) throw new
belowZeroException("below 0!");
if($nArg > 9) throw new
aboveNineException("above 9!");
}
}
try {
$objCouldGoWrong = new clsCouldGoWrong(-1);
}
catch (belowZeroException $e) {
echo "things messed up! The error was: ".
$e->getMessage();
}
catch (aboveNineException $e) {
echo "things didn't work out in a different
way. the error was: ".$e->getMessage();
}
We can catch an unlimited amount of exception types depending on our requirements. A very powerful error-handling mechanism indeed!
Static methods
PHP5 introduces static methods. If we declare a method static it can be called from outside the object in the well known form className::methodName()
instanceOf()
With the instanceOf() function we can check whether a certain object is an instance of a particular class.
__toString() method
In PHP5 we can create a special method called __toString() in which we can define the string value we end up with when casting the object to a string.
final keyword
With the keyword final we can prevent methods from being overridden in extending classes.
This article by no means claims to be complete. It's a brief summary with some easy examples explaining some of the many new features in the Zend Engine 2.0. Apart from the Zend Engine 2.0 which forms the core of PHP5 more new features have been added to PHP5. The most important ones are SimpleXML, SQLite and a completely revamped DOM XML API, now fully W3C DOM Level 2 compliant. I will publish separate articles on these matters later and add links to them here below this page as well.