PHP Objects, Patterns and Practice (3rd edition)

(Barry) #1

CHAPTER 15 ■ AN INTRODUCTION TO PEAR AND PYRUS


The way that PEAR_Error pollutes a method’s return value was an unfortunate necessity before the
advent of PHP 5. With PHP 4 at or near the end of its life, it’s no surprise that PEAR_Error has been
deprecated.
Although many packages continue to use PEAR_Error and will probably do so for some time, more
are beginning to use PEAR_Exception. If you were to use the XML_Feed_Parser package, for example you
would be catching exceptions rather than testing return types:


$source="notthere";
try {
$myfeed = new XML_Feed_Parser( $source );


} catch ( XML_Feed_Parser_Exception $e ) {
print "message: ". $e->getMessage() ."\n";
print "code: ". $e->getCode() ."\n";
print "error class: ". $e->getErrorClass() ."\n";
print "error method: ".$e->getErrorMethod() ."\n";
print "trace: ". $e->getTraceAsString()."\n";
print "error data: ";
print_r( $e->getErrorData() );
}


Typically. a PEAR package will extend PEAR_Exception, partly so that it can add any functionality it
needs, but mainly so that you can use your catch clause to distinguish between Exception types.
PEAR_Exception, of course, itself extends Exception, so you get the standard methods I covered in
Chapter 4. You also benefit from some additions. getErrorClass() and getErrorMethod(), for example,
tell you the class and method from which the error originated. getErrorData() may include additional
error information in an associative array, although this is left for extending classes to implement. Before
being thrown to you, a PEAR_Exception object can be initialized with another Exception or with an array
of Exception objects. In this way, PEAR packages can wrap Exception objects. You can get at wrapped
exceptions by calling PEAR::getCause(). This will either return a wrapped Exception object, an array if
there is more than one, or null if none are found.
PEAR_Exception also uses the Observer pattern, allowing you to register callback functions or
methods that will be called whenever an exception is thrown. First, let’s create some error conditions:


class MyPearException extends PEAR_Exception {
}


class MyFeedThing {
function acquire( $source ) {
try {
$myfeed = @new XML_Feed_Parser( $source );
return $myfeed;
} catch ( XML_Feed_Parser_Exception $e ) {
throw new MyPearException( "feed acquisition failed", $e );
}
}
}


I extend PEAR_Exception and create a simple class that wraps XML_Feed_Parser. If the
XML_Feed_Parser constructor throws an exception, I catch it and pass it to the constructor of
MyPearException, which I then rethrow. This trick allows me to raise my own error while bundling the
root cause.
Here is a client class and a couple of lines of code to invoke it:

Free download pdf