<?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
-->