<?xml version="1.0" encoding="utf-8"?> <!-- $Revision$ --> <chapter xml:id="language.exceptions" xmlns="http://docbook.org/ns/docbook"> <title>Exceptions</title> <sect1 xml:id="language.exceptions.extending"> <title>Extending Exceptions</title> <para> A User defined Exception class can be defined by extending the built-in Exception class. The members and properties below, show what is accessible within the child class that derives from the built-in Exception class. </para> <example> <title>The Built in Exception class</title> <programlisting role="php"> <![CDATA[ <?php class Exception { protected $message = 'Unknown exception'; // exception message private $string; // __toString cache protected $code = 0; // user defined exception code protected $file; // source filename of exception protected $line; // source line of exception private $trace; // backtrace private $previous; // previous exception if nested exception public function __construct($message = null, $code = 0, Exception $previous = null); final private function __clone(); // Inhibits cloning of exceptions. final public function getMessage(); // message of exception final public function getCode(); // code of exception final public function getFile(); // source filename final public function getLine(); // source line final public function getTrace(); // an array of the backtrace() final public function getPrevious(); // previous exception final public function getTraceAsString(); // formatted string of trace // Overrideable public function __toString(); // formatted string for display } ?> ]]> </programlisting> </example> <para> If a class extends the built-in Exception class and re-defines the <link linkend="language.oop5.decon">constructor</link>, it is highly recommended that it also call <link linkend="language.oop5.paamayim-nekudotayim">parent::__construct()</link> to ensure all available data has been properly assigned. The <link linkend="language.oop5.magic">__toString()</link> method can be overridden to provide a custom output when the object is presented as a string. </para> <note> <para> Exceptions cannot be cloned. Attempting to <link linkend="language.oop5.cloning">clone</link> an Exception will result in a fatal <constant>E_ERROR</constant> error. </para> </note> <example> <title>Extending the Exception class (PHP 5.3.0+)</title> <programlisting role="php"> <![CDATA[ <?php /** * Define a custom exception class */ class MyException extends Exception { // Redefine the exception so message isn't optional public function __construct($message, $code = 0, Exception $previous = null) { // some code // make sure everything is assigned properly parent::__construct($message, $code, $previous); } // custom string representation of object public function __toString() { return __CLASS__ . ": [{$this->code}]: {$this->message}\n"; } public function customFunction() { echo "A custom function for this type of exception\n"; } } /** * Create a class to test the exception */ class TestException { public $var; const THROW_NONE = 0; const THROW_CUSTOM = 1; const THROW_DEFAULT = 2; function __construct($avalue = self::THROW_NONE) { switch ($avalue) { case self::THROW_CUSTOM: // throw custom exception throw new MyException('1 is an invalid parameter', 5); break; case self::THROW_DEFAULT: // throw default one. throw new Exception('2 is not allowed as a parameter', 6); break; default: // No exception, object will be created. $this->var = $avalue; break; } } } // Example 1 try { $o = new TestException(TestException::THROW_CUSTOM); } catch (MyException $e) { // Will be caught echo "Caught my exception\n", $e; $e->customFunction(); } catch (Exception $e) { // Skipped echo "Caught Default Exception\n", $e; } // Continue execution var_dump($o); // Null echo "\n\n"; // Example 2 try { $o = new TestException(TestException::THROW_DEFAULT); } catch (MyException $e) { // Doesn't match this type echo "Caught my exception\n", $e; $e->customFunction(); } catch (Exception $e) { // Will be caught echo "Caught Default Exception\n", $e; } // Continue execution var_dump($o); // Null echo "\n\n"; // Example 3 try { $o = new TestException(TestException::THROW_CUSTOM); } catch (Exception $e) { // Will be caught echo "Default Exception caught\n", $e; } // Continue execution var_dump($o); // Null echo "\n\n"; // Example 4 try { $o = new TestException(); } catch (Exception $e) { // Skipped, no exception echo "Default Exception caught\n", $e; } // Continue execution var_dump($o); // TestException echo "\n\n"; ?> ]]> </programlisting> <note> <para> Versions of PHP 5, prior to PHP 5.3.0 do not support nesting of exceptions. The following code fragment can be used as a replacement MyException class if you wish to run this example. </para> <programlisting role="php"> <![CDATA[ <?php /** * Define a custom exception class */ class MyException extends Exception { // Redefine the exception so message isn't optional public function __construct($message, $code = 0) { // some code // make sure everything is assigned properly parent::__construct($message, $code); } // custom string representation of object public function __toString() { return __CLASS__ . ": [{$this->code}]: {$this->message}\n"; } public function customFunction() { echo "A custom function for this type of exception\n"; } } ?> ]]> </programlisting> </note> </example> </sect1> <simplesect xml:id="language.exceptions.introduction"> <para> PHP 5 has an exception model similar to that of other programming languages. An exception can be &throw;n, and caught ("&catch;ed") within PHP. Code may be surrounded in a &try; block, to facilitate the catching of potential exceptions. Each &try; must have at least one corresponding &catch; or &finally; block. </para> <para> The thrown object must be an instance of the <classname>Exception</classname> class or a subclass of <classname>Exception</classname>. Trying to throw an object that is not will result in a PHP Fatal Error. </para> </simplesect> <simplesect xml:id="language.exceptions.catch"> <title><literal>catch</literal></title> <para> Multiple &catch; blocks can be used to catch different classes of exceptions. Normal execution (when no exception is thrown within the &try; block) will continue after that last &catch; block defined in sequence. Exceptions can be &throw;n (or re-thrown) within a &catch; block. </para> <para> When an exception is thrown, code following the statement will not be executed, and PHP will attempt to find the first matching &catch; block. If an exception is not caught, a PHP Fatal Error will be issued with an "<literal>Uncaught Exception ...</literal>" message, unless a handler has been defined with <function>set_exception_handler</function>. </para> </simplesect> <simplesect xml:id="language.exceptions.finally"> <title><literal>finally</literal></title> <para> In PHP 5.5 and later, a &finally; block may also be specified after or instead of &catch; blocks. Code within the &finally; block will always be executed after the &try; and &catch; blocks, regardless of whether an exception has been thrown, and before normal execution resumes. </para> </simplesect> <simplesect xml:id="language.exceptions.notes"> &reftitle.notes; <note> <para> Internal PHP functions mainly use <link linkend="ini.error-reporting">Error reporting</link>, only modern <link linkend="language.oop5">Object oriented</link> extensions use exceptions. However, errors can be simply translated to exceptions with <link linkend="class.errorexception">ErrorException</link>. </para> </note> <tip> <para> The <link linkend="intro.spl">Standard PHP Library (SPL)</link> provides a good number of <link linkend="spl.exceptions">built-in exceptions</link>. </para> </tip> </simplesect> <simplesect xml:id="language.exceptions.examples"> &reftitle.examples; <example> <title>Throwing an Exception</title> <programlisting role="php"> <![CDATA[ <?php function inverse($x) { if (!$x) { throw new Exception('Division by zero.'); } return 1/$x; } try { echo inverse(5) . "\n"; echo inverse(0) . "\n"; } catch (Exception $e) { echo 'Caught exception: ', $e->getMessage(), "\n"; } // Continue execution echo "Hello World\n"; ?> ]]> </programlisting> &example.outputs; <screen> <![CDATA[ 0.2 Caught exception: Division by zero. Hello World ]]> </screen> </example> <example> <title>Exception handling with a <literal>finally</literal> block</title> <programlisting role="php"> <![CDATA[ <?php function inverse($x) { if (!$x) { throw new Exception('Division by zero.'); } return 1/$x; } try { echo inverse(5) . "\n"; } catch (Exception $e) { echo 'Caught exception: ', $e->getMessage(), "\n"; } finally { echo "First finally.\n"; } try { echo inverse(0) . "\n"; } catch (Exception $e) { echo 'Caught exception: ', $e->getMessage(), "\n"; } finally { echo "Second finally.\n"; } // Continue execution echo "Hello World\n"; ?> ]]> </programlisting> &example.outputs; <screen> <![CDATA[ 0.2 First finally. Caught exception: Division by zero. Second finally. Hello World ]]> </screen> </example> <example> <title>Nested Exception</title> <programlisting role="php"> <![CDATA[ <?php class MyException extends Exception { } class Test { public function testing() { try { try { throw new MyException('foo!'); } catch (MyException $e) { // rethrow it throw $e; } } catch (Exception $e) { var_dump($e->getMessage()); } } } $foo = new Test; $foo->testing(); ?> ]]> </programlisting> &example.outputs; <screen> <![CDATA[ string(4) "foo!" ]]> </screen> </example> </simplesect> </chapter> <!-- Keep this comment at the end of the file Local variables: mode: sgml sgml-omittag:t sgml-shorttag:t sgml-minimize-attributes:nil sgml-always-quote-attributes:t sgml-indent-step:1 sgml-indent-data:t indent-tabs-mode:nil sgml-parent-document:nil sgml-default-dtd-file:"~/.phpdoc/manual.ced" sgml-exposed-tags:nil sgml-local-catalogs:nil sgml-local-ecat-files:nil End: vim600: syn=xml fen fdm=syntax fdl=2 si vim: et tw=78 syn=sgml vi: ts=1 sw=1 -->