<?xml version="1.0" encoding="iso-8859-1"?>
<!-- $Revision: 1.10 $ -->
 <chapter xml:id="language.exceptions" xmlns="http://docbook.org/ns/docbook">
  <title>Exceptions</title>

  <para>
   PHP 5 has an exception model similar to that of other programming languages.
   An exception can be <literal>throw</literal>n, and caught
   ("<literal>catch</literal>ed") within PHP. Code may be surrounded in a
   <literal>try</literal> block, to facilitate the catching of potential
   exceptions. Each <literal>try</literal> must have at least one
   corresponding <literal>catch</literal> block. Multiple
   <literal>catch</literal> blocks can be used to catch different classes of
   exeptions. Normal execution (when no exception is thrown within the
   <literal>try</literal> block, or when a <literal>catch</literal> matching
   the thrown exception's class is not present) will continue after that last catch
   block defined in sequence. Exceptions can be <literal>throw</literal>n (or
   re-thrown) within a <literal>catch</literal> 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
   <literal>catch</literal> 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>
  <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 built-in exceptions.
   </para>
  </tip>
   <example>
    <title>Throwing an Exception</title>
    <programlisting role="php">
<![CDATA[
<?php
function inverse($x) {
    if (!$x) {
        throw new Exception('Division by zero.');
    }
    else 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';
?>
]]>
    </programlisting>
    &example.outputs;
    <screen>
<![CDATA[
0.2
Caught exception: Division by zero.
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>
   
  <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
    protected $code = 0;                        // user defined exception code
    protected $file;                            // source filename of exception
    protected $line;                            // source line of exception

    function __construct($message = null, $code = 0);

    final function getMessage();                // message of exception 
    final function getCode();                   // code of exception
    final function getFile();                   // source filename
    final function getLine();                   // source line
    final function getTrace();                  // an array of the backtrace()
    final function getTraceAsString();          // formatted string of trace

    /* Overrideable */
    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>
   <example>
    <title>Extending the Exception class</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) {
        // 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";
    }
}


/**
 * 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);
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);
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);
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);
echo "\n\n";
?>
]]>
    </programlisting>
   </example>
  </sect1>

 </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:"../../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
-->