[doc-en] master: Refactor error/exception pages into an "Error handling" page (#320)

From: Date: Tue, 06 Oct 2026 12:40:39 +0000
Subject: [doc-en] master: Refactor error/exception pages into an "Error handling" page (#320)
Groups: php.doc.cvs 
Request: Send a blank email to doc-cvs+get-23813@lists.php.net to get a copy of this message
Author: Gina Peter Banyard (Girgias) Committer: GitHub (web-flow) Pusher: lacatoire Date: 2026-10-06T14:40:35+02:00 Commit: https://github.com/php/doc-en/commit/7c915c0c28b8e2e4306333c64602ee4800c73754 Raw diff: https://github.com/php/doc-en/commit/7c915c0c28b8e2e4306333c64602ee4800c73754.diff Refactor error/exception pages into an "Error handling" page (#320) * Refactor error pages into something more generic. This renames traditional errors to diagnostic errors Create a page about error handling in PHP describing how to handle Throwable Errors (Exceptions) and diagnostics. > Inspired from the Rust docs. Create dedicated pages for: - throw - try-catch - finally * Clarify finally and return example * Expand finally and exit() interaction section * Indent * Make intereaction between return and finally a section * Add an initial section about yield and finally * Clarify what call-stack unwinding means * Use variable in catch statement Usage without it is explained in the following section * Add error_reporting() check when using a custom error handler * Cleanup docs related to @ operator Also fix part of the set_error_handler() docs * Nits * Front load logic of finally behaviour with various other bits * Document weird finally exit and generator edge case * Add missing parenthesis Co-authored-by: George Peter Banyard <girgias@php.net> * Update links to the removed exception and error pages Point the throw, try, catch and finally entities and the remaining references to the anchors of the new Error handling and control structure pages, and include the new chapter in manual.xml. * Port master changes to the new error handling pages Restore the $Revision$ markers, mark the chapter as interactive, and carry over the changes made to the removed pages since the branch was created: exception chaining with finally, explicit nullable type in the custom exception example, clone warning, FiberError in the hierarchy, 8.5.0 changelog entry, missing example outputs and the runnable throw expression example. * Fix inaccuracies in the error handling pages Correct the outputs of the finally examples, the claim that exit is the only case skipping a finally block, the version ranges of the exit and generator edge case, and the statements about the global exception handler and about fatal diagnostics. * Use exceptionname for exception classes and leave the stomp page untouched The stomp extension is migrating to doc-extensions, so its page is restored to master. The old language.exceptions anchor is kept as an alias so that the existing reference from that page still resolves. * Use simpara for inline-only paragraphs touched by the refactor * Address review feedback on the error handling pages --------- Co-authored-by: Anna Filina <afilina@gmail.com> Co-authored-by: Louis-Arnaud <la.catoire@gmail.com> Changed paths: A language/control-structures/finally.xml A language/control-structures/throw.xml A language/control-structures/try-catch.xml A language/error-handling.xml D language/errors.xml D language/errors/basics.xml D language/errors/php7.xml D language/exceptions.xml M appendices/migration70/incompatible/error-handling.xml M appendices/reserved.xml M appendices/tokens.xml M entities/entities.php.ent M language/control-structures.xml M language/oop5/basic.xml M language/oop5/changelog.xml M language/operators/precedence.xml M language/predefined/exceptions.xml M manual.xml M reference/dom/domexception.xml M reference/errorfunc/functions/get-exception-handler.xml M reference/errorfunc/functions/set-exception-handler.xml M reference/pdo/connections.xml M reference/pdo/error-handling.xml M reference/pdo/pdoexception.xml M reference/snmp/snmpexception.xml Diff: diff --git a/appendices/migration70/incompatible/error-handling.xml b/appendices/migration70/incompatible/error-handling.xml index 37e9a31525b8..5b9a2adc3345 100644 --- a/appendices/migration70/incompatible/error-handling.xml +++ b/appendices/migration70/incompatible/error-handling.xml @@ -17,12 +17,12 @@ <classname>Error</classname> exceptions). </para> - <para> - A fuller description of how errors operate in PHP 7 can be found - <link linkend="language.errors.php7">on the PHP 7 errors page</link>. This + <simpara> + A more complete description of how errors operate in PHP can be found + <link linkend="language.error-handling.throwable">on the Throwable errors page</link>. This migration guide will merely enumerate the changes that affect backward compatibility. - </para> + </simpara> <sect3 xml:id="migration70.incompatible.error-handling.set-exception-handler"> <title> diff --git a/appendices/reserved.xml b/appendices/reserved.xml index 399b84d2bc8a..5575cb663b63 100644 --- a/appendices/reserved.xml +++ b/appendices/reserved.xml @@ -55,7 +55,7 @@ <link linkend="control-structures.switch">case</link> </entry> <entry> - <link linkend="language.exceptions">catch</link> + <link linkend="control-structures.catch">catch</link> </entry> <entry> <link linkend="language.oop5.basic.class">class</link> @@ -134,7 +134,7 @@ <link linkend="language.oop5.final">final</link> </entry> <entry> - <link linkend="language.exceptions">finally</link> + <link linkend="control-structures.finally">finally</link> </entry> <entry> <link linkend="functions.arrow">fn</link> (as of PHP 7.4) @@ -236,13 +236,13 @@ <link linkend="control-structures.switch">switch</link> </entry> <entry> - <link linkend="language.exceptions">throw</link> + <link linkend="control-structures.throw">throw</link> </entry> <entry> <link linkend="language.oop5.traits">trait</link> </entry> <entry> - <link linkend="language.exceptions">try</link> + <link linkend="control-structures.try">try</link> </entry> <entry> <function>unset</function> diff --git a/appendices/tokens.xml b/appendices/tokens.xml index 7a4223faba29..30a4521916ca 100644 --- a/appendices/tokens.xml +++ b/appendices/tokens.xml @@ -180,7 +180,7 @@ defined('T_FN') || define('T_FN', 10001); (<type>int</type>) </entry> <entry>catch</entry> - <entry><xref linkend="language.exceptions"/></entry> + <entry><xref linkend="control-structures.catch"/></entry> </row> <row xml:id="constant.t-class"> <entry> @@ -557,7 +557,7 @@ defined('T_FN') || define('T_FN', 10001); (<type>int</type>) </entry> <entry>finally</entry> - <entry><xref linkend="language.exceptions"/></entry> + <entry><xref linkend="control-structures.finally"/></entry> </row> <row xml:id="constant.t-fn"> <entry> @@ -1255,7 +1255,7 @@ defined('T_FN') || define('T_FN', 10001); (<type>int</type>) </entry> <entry>throw</entry> - <entry><xref linkend="language.exceptions"/></entry> + <entry><xref linkend="control-structures.throw"/></entry> </row> <row xml:id="constant.t-trait"> <entry> @@ -1279,7 +1279,7 @@ defined('T_FN') || define('T_FN', 10001); (<type>int</type>) </entry> <entry>try</entry> - <entry><xref linkend="language.exceptions"/></entry> + <entry><xref linkend="control-structures.try"/></entry> </row> <row xml:id="constant.t-unset"> <entry> diff --git a/entities/entities.php.ent b/entities/entities.php.ent index 8736cb6e803d..f83651342e48 100644 --- a/entities/entities.php.ent +++ b/entities/entities.php.ent @@ -21,7 +21,7 @@ There are a few <filename> tossed near and there. <entity name="callback.cmp"><methodsynopsis><type>int</type><methodname><replaceable>callback</replaceable></methodname><methodparam><type>mixed</type><parameter>a</parameter></methodparam><methodparam><type>mixed</type><parameter>b</parameter></methodparam></methodsynopsis></entity> -<entity name="catch"><link linkend="language.exceptions.catch"><literal>catch</literal></link></entity> +<entity name="catch"><link linkend="control-structures.catch"><literal>catch</literal></link></entity> <entity name="const"><link linkend="language.constants.syntax"><literal>const</literal></link></entity> @@ -29,7 +29,7 @@ There are a few <filename> tossed near and there. <entity name="false"><constant>false</constant></entity> -<entity name="finally"><link linkend="language.exceptions.finally"><literal>finally</literal></link></entity> +<entity name="finally"><link linkend="control-structures.finally"><literal>finally</literal></link></entity> <entity name="float"><type>float</type></entity> @@ -71,11 +71,11 @@ There are a few <filename> tossed near and there. <entity name="string"><type>string</type></entity> -<entity name="throw"><link linkend="language.exceptions"><literal>throw</literal></link></entity> +<entity name="throw"><link linkend="control-structures.throw"><literal>throw</literal></link></entity> <entity name="true"><constant>true</constant></entity> -<entity name="try"><link linkend="language.exceptions"><literal>try</literal></link></entity> +<entity name="try"><link linkend="control-structures.try"><literal>try</literal></link></entity> <entity name="use.namespace"><link linkend="language.namespaces.importing"><literal>use</literal></link></entity> diff --git a/language/control-structures.xml b/language/control-structures.xml index b9a6b334e9b5..437eb3ea95af 100644 --- a/language/control-structures.xml +++ b/language/control-structures.xml @@ -54,6 +54,9 @@ &language.control-structures.require-once; &language.control-structures.include-once; &language.control-structures.goto; + &language.control-structures.throw; + &language.control-structures.try-catch; + &language.control-structures.finally; </chapter> diff --git a/language/control-structures/finally.xml b/language/control-structures/finally.xml new file mode 100644 index 000000000000..f2146d26696b --- /dev/null +++ b/language/control-structures/finally.xml @@ -0,0 +1,488 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- $Revision$ --> +<sect1 xml:id="control-structures.finally" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink"> + <title>finally</title> + <?phpdoc print-version-for="finally"?> + <simpara> + 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, even if a &return; or &yield; statement is encountered, + or if a <exceptionname>Throwable</exceptionname> error is not caught or is rethrown. + It will be executed prior to resuming the normal execution flow. + The only exception to this rule is when the script is terminated abruptly, + such as by a call to <function>exit</function> or by a fatal error + (for example when the maximum execution time is exceeded). + </simpara> + <example> + <title><exceptionname>Throwable</exceptionname> error handling with a &finally; block</title> + <programlisting role="php"> +<![CDATA[ +<?php +function inverse($x) { + return 1/$x; +} + +try { + echo inverse(5) . "\n"; +} catch (\DivisionByZeroError $e) { + echo 'Caught error: ', $e->getMessage(), "\n"; +} finally { + echo "First finally.\n"; +} + +try { + echo inverse(0) . "\n"; +} catch (\DivisionByZeroError $e) { + echo 'Caught error: ', $e->getMessage(), "\n"; +} finally { + echo "Second finally.\n"; +} + +// Continue execution +echo "Hello World\n"; +]]> + </programlisting> + &example.outputs.8; + <screen> +<![CDATA[ +0.2 +First finally. +Caught error: Division by zero +Second finally. +Hello World +]]> + </screen> + </example> + + <simpara> + When the call stack is unwound after a <exceptionname>Throwable</exceptionname> error + has been thrown, all &finally; blocks it encounters along the way will be executed. + In other words, nested &finally; blocks are executed even if the + <exceptionname>Throwable</exceptionname> error is not caught by an adjacent + &catch; block. + </simpara> + <example> + <title>All &finally; block will be executed</title> + <programlisting role="php"> + <![CDATA[ +<?php +try { + try { + throw new Exception(); + } finally { + echo "Inner finally\n"; + } +} catch (Exception $e) { +} finally { + echo "Outer finally\n"; +} +]]> + </programlisting> + &example.outputs; + <screen> +<![CDATA[ +Inner finally +Outer finally +]]> + </screen> + </example> + + <sect2> + <title>Interaction between a &finally; block and a &return; statement</title> + <simpara> + One notable interaction is between the &finally; block and a &return; statement. + If a &return; statement is encountered inside either the &try; or the &catch; blocks, + the &finally; block will still be executed. Moreover, the &return; statement is + evaluated when encountered, but the result will be returned after the &finally; block + is executed. Additionally, if the &finally; block also contains a &return; statement, + the value from the &finally; block is returned. + </simpara> + <example> + <title>Interaction between &return; in &finally; block and a previous &return;</title> + <programlisting role="php"> +<![CDATA[ +<?php +function testReturnTry() { + try { + echo 'Within try', "\n"; + return 'try'; + } finally { + echo 'Within finally', "\n"; + return 'finally'; + } +} + +function testReturnCatch() { + try { + throw new Exception('foo'); + } catch (Exception $e) { + echo 'Within catch', "\n"; + return 'catch'; + } finally { + echo 'Within finally', "\n"; + return 'finally'; + } +} + +echo testReturnTry(), "\n"; +echo testReturnCatch(), "\n"; + +]]> + </programlisting> + &example.outputs; + <screen> +<![CDATA[ +Within try +Within finally +finally +Within catch +Within finally +finally +]]> + </screen> + </example> + <example> + <title>Interaction between the &finally; block and &return;</title> + <programlisting role="php"> +<![CDATA[ +<?php +function testReturnTry() { + try { + return 'try'; + } finally { + echo 'finally '; + } +} + +function testReturnCatch() { + try { + throw new Exception('foo'); + } catch (Exception $e) { + return 'catch'; + } finally { + echo 'finally '; + } +} + +echo testReturnTry(), "\n"; +echo testReturnCatch(), "\n"; +]]> + </programlisting> + &example.outputs; + <screen> +<![CDATA[ +finally try +finally catch +]]> + </screen> + </example> + </sect2> + + <sect2> + <title>Interaction between a &finally; block and an exception thrown in a &try; block</title> + <simpara> + If both the &try; block and the &finally; block throw an exception, + the exception thrown from the &finally; block is the one that is propagated, + and the exception thrown from the &try; block will be used as its previous exception. + </simpara> + <example> + <title>Exception in try and in finally</title> + <programlisting role="php"> +<![CDATA[ +<?php + +try { + try { + throw new Exception(message: 'Third', previous: new Exception('Fourth')); + } finally { + throw new Exception(message: 'First', previous: new Exception('Second')); + } +} catch (Exception $e) { + var_dump( + $e->getMessage(), + $e->getPrevious()->getMessage(), + $e->getPrevious()->getPrevious()->getMessage(), + $e->getPrevious()->getPrevious()->getPrevious()->getMessage(), + ); +} +]]> + </programlisting> + &example.outputs; + <screen> +<![CDATA[ +string(5) "First" +string(6) "Second" +string(5) "Third" +string(6) "Fourth" +]]> + </screen> + </example> + </sect2> + + <sect2> + <title> + Behaviour of a &finally; block in a + <link linkend="language.generators">Generator</link> + </title> + + <simpara> + If during the traversal of a generator a <exceptionname>Throwable</exceptionname> + error is thrown, the &finally; within the generator will be executed, + as it is the previous element of the call stack. + </simpara> + <example> + <title> + &finally; block being run when an <exceptionname>Exception</exceptionname> + has been thrown + </title> + <programlisting role="php"> + <![CDATA[ +<?php +function generate() +{ + try { + yield 1; + yield 2; + } catch(\Exception $e) { + echo 'catch'; + } finally { + echo "finally\n"; + } +} + +try { + foreach (generate() as $i) { + echo $i, "\n"; + throw new Exception(); + } +} catch(Exception $e) { + echo 'outer catch'; +} +]]> + </programlisting> + &example.outputs.similar; + <screen> +<![CDATA[ +1 +finally +outer catch +]]> + </screen> + </example> + + <simpara> + It is possible to &yield; within a &finally; block but if a + <exceptionname>Throwable</exceptionname> error occurs and is not caught within + the &foreach; a <literal>Cannot yield from finally in a force-closed + generator</literal> <exceptionname>Error</exceptionname> is thrown. + </simpara> + <example> + <title> + Error when &yield;ing in &finally; block when an <exceptionname>Exception</exceptionname> + has been thrown + </title> + <programlisting role="php"> +<![CDATA[ +<?php +function generate() +{ + try { + yield 1; + yield 2; + } catch(\Exception $e) { + echo 'catch'; + } finally { + echo "finally\n"; + yield 3; + } +} + +try { + foreach (generate() as $i) { + echo $i, "\n"; + throw new Exception(); + } +} catch(Exception $e) { + echo 'outer catch'; +} +]]> + </programlisting> + &example.outputs.similar; + <screen> +<![CDATA[ +1 +finally + +Fatal error: Uncaught Exception in /in/GbFmu:19 +Stack trace: +#0 {main} + +Next Error: Cannot yield from finally in a force-closed generator in /in/GbFmu:12 +Stack trace: +#0 /in/GbFmu(19): generate() +#1 {main} + thrown in /in/GbFmu on line 12 +]]> + </screen> + </example> + </sect2> + + <sect2> + <title>Interaction between a &finally; block and a call to <function>exit</function></title> + <simpara> + When <function>exit</function> is called within a &try; or a &catch; block + all &finally; blocks are skipped. + </simpara> + <example> + <title>Interaction between &finally; block and <function>exit</function> called in &try; block</title> + <programlisting role="php"> +<![CDATA[ +<?php +try { + echo 'quit'; + exit(0); +} finally { + echo 'finally'; +} +]]> + </programlisting> + &example.outputs; + <screen> +<![CDATA[ +quit +]]> + </screen> + </example> + <example> + <title>Interaction between &finally; block and <function>exit</function> called in &catch; block</title> + <programlisting role="php"> +<![CDATA[ +<?php +try { + throw new Exception('foo'); +} catch (Exception $e) { + echo 'catch'; + exit(0); +} finally { + echo 'finally '; +} +]]> + </programlisting> + &example.outputs; + <screen> +<![CDATA[ +catch +]]> + </screen> + </example> + <example> + <title>All &finally; blocks are skipped when <function>exit</function> is called</title> + <programlisting role="php"> +<![CDATA[ +<?php +try { + try { + echo 'quit'; + exit(0); + } finally { + echo 'inner finally '; + } +} finally { + echo 'outer finally'; +} +]]> + </programlisting> + &example.outputs; + <screen> +<![CDATA[ +quit +]]> + </screen> + </example> + + <simpara> + When <function>exit</function> is called within a &finally; block, + all other outer &finally; blocks are skipped. + </simpara> + <example> + <title>Skipping outer &finally; block by calling <function>exit</function></title> + <programlisting role="php"> +<![CDATA[ +<?php +try { + try { + echo 'try', "\n"; + } finally { + echo 'inner finally '; + exit(0); + } +} finally { + echo 'outer finally'; +} +]]> + </programlisting> + &example.outputs; + <screen> +<![CDATA[ +try +inner finally +]]> + </screen> + </example> + + <sect3> + <title>Edge case of calling <function>exit</function> in a &foreach; over a generator</title> + <simpara> + This one edge case behaviour is highly dependent on which version of PHP + the code is executed. + </simpara> + + <informalexample> + <programlisting role="php"> +<![CDATA[ +<?php +function generate() +{ + try { + yield 1; + yield 2; + } catch(\Exception $e) { + echo 'catch'; + } finally { + echo "inner finally\n"; + } +} + +try { + foreach (generate() as $i) { + echo $i, "\n"; + exit(0); + } +} finally { + echo "outer finally\n"; +} +]]> + </programlisting> + <simpara> + Output of the above example prior to PHP 7.1.14, in PHP 7.2.0 and 7.2.1, + and as of PHP 8.0.0 + </simpara> + <screen> +<![CDATA[ +1 +inner finally +]]> + </screen> + <simpara> + Output of the above example as of PHP 7.1.14 and 7.2.2, + and prior to PHP 8.0.0 + </simpara> + <screen> +<![CDATA[ +1 +]]> + </screen> + </informalexample> + </sect3> + </sect2> +</sect1> diff --git a/language/control-structures/throw.xml b/language/control-structures/throw.xml new file mode 100644 index 000000000000..9bd0b2f993a1 --- /dev/null +++ b/language/control-structures/throw.xml @@ -0,0 +1,135 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- $Revision$ --> +<sect1 xml:id="control-structures.throw" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink"> + <title>throw</title> + <?phpdoc print-version-for="throw"?> + <simpara> + The &throw; keyword is an expression and may be used in any expression context. + It takes an instance of a <exceptionname>Throwable</exceptionname> object as an + argument. + </simpara> + <caution> + <simpara> + Prior to PHP 8.0, the &throw; keyword was a statement and not an expression. + </simpara> + </caution> + <para> + Attempting to &throw; a non-<exceptionname>Throwable</exceptionname> object will + throw an <exceptionname>Error</exceptionname>. + + <example> + <title>Throwing a non-<exceptionname>Throwable</exceptionname> object</title> + <programlisting role="php"> +<![CDATA[ +<?php +throw new class {}; +]]> + </programlisting> + &example.outputs.similar; + <screen> +<![CDATA[ +PHP Fatal error: Uncaught Error: Cannot throw objects that do not implement Throwable in Command line code:1 +Stack trace: +#0 {main} +]]> + </screen> + </example> + </para> + + <simpara> + After using &throw; the normal flow of execution is halted and the call stack + is unwound until the object is caught by a &catch; block or the global scope + is reached. In the latter case, the program is terminated with + a fatal error containing the stack trace indicating where the + <exceptionname>Throwable</exceptionname> object has been thrown. + </simpara> + <example> + <title>Throwing an Exception in the global scope</title> + <programlisting role="php"> +<![CDATA[ +<?php +echo "Before exception\n"; +throw new Exception('Stop execution'); +echo "After exception\n"; +]]> + </programlisting> + &example.outputs.similar; + <screen> +<![CDATA[ +Before exception +PHP Fatal error: Uncaught Exception: Stop execution in Command line code:2 +Stack trace: +#0 {main} + thrown in Command line code on line 2 +]]> + </screen> + </example> + <example> + <title>Throwing an Exception in a function</title> + <programlisting role="php"> + <![CDATA[ +<?php + +function foo() { + echo "Before exception\n"; + throw new Exception('Stop execution'); + echo "After exception\n"; +} + +foo(); +]]> + </programlisting> + &example.outputs.similar; + <screen> +<![CDATA[ +Before exception +PHP Fatal error: Uncaught Exception: Stop execution in Command line code:3 +Stack trace: +#0 Command line code(7): foo() +#1 {main} + thrown in Command line code on line 3 +]]> + </screen> + </example> + + <simpara> + As &throw; is an expression it can be used to branch out on the result + of another expression if its value is inappropriate. + </simpara> + <example> + <title>Using throw as an expression</title> + <simpara>Only permitted as of PHP 8.0.0.</simpara> + <programlisting role="php"> +<![CDATA[ +<?php + +function test() { + do_something_risky() or throw new Exception('It did not work'); +} + +function do_something_risky() { + return false; // Simulate failure +} + +try { + test(); +} catch (Exception $e) { + print $e->getMessage(); +} +]]> + </programlisting> + &example.outputs; + <screen> +<![CDATA[ +It did not work +]]> + </screen> + </example> + + <simpara> + It is possible to handle a thrown <exceptionname>Throwable</exceptionname> by using + a <link linkend="control-structures.try-catch">try-catch</link> block. + See the <link linkend="language.error-handling.throwable">error handling</link> + section for more information. + </simpara> +</sect1> diff --git a/language/control-structures/try-catch.xml b/language/control-structures/try-catch.xml new file mode 100644 index 000000000000..c372bf09061d --- /dev/null +++ b/language/control-structures/try-catch.xml @@ -0,0 +1,235 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- $Revision$ --> +<sect1 xml:id="control-structures.try-catch" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink"> + <title>Try...Catch</title> + <sect2 xml:id="control-structures.try" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink"> + <title>try</title> + <?phpdoc print-version-for="try"?> + <simpara> + A &try; block delimits a segment of code which might &throw; + a <exceptionname>Throwable</exceptionname> error that needs handling. + A &try; block <emphasis>must</emphasis> have at least one corresponding + &catch; or &finally; block. + </simpara> + <simpara> + When a <exceptionname>Throwable</exceptionname> error is thrown in a &try; block + PHP will attempt to find the first matching &catch; block to handle the + error. If none can be found, it will unwind the call stack until one is found or a global error handler is reached. + </simpara> + <note> + <simpara> + It's possible to add a handler for any uncaught + <exceptionname>Throwable</exceptionname> with + <function>set_exception_handler</function>. + This is similar to wrapping the entire code in a &try;-&catch; block. + </simpara> + </note> + </sect2> + <sect2 xml:id="control-structures.catch" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink"> + <title>catch</title> + <?phpdoc print-version-for="catch"?> + <simpara> + A &catch; block defines how to respond to a thrown <exceptionname>Throwable</exceptionname> error. + It specifies one or more subclasses of <exceptionname>Throwable</exceptionname> + (most commonly <exceptionname>Exception</exceptionname>) it can handle, and + optionally a variable to which to assign the exception. + </simpara> + <simpara> + The first &catch; block + that matches the class of the thrown <exceptionname>Throwable</exceptionname> + object will handle the error. + Normal execution resumes after the &catch; block without entering any other matching &catch; blocks. + </simpara> + <example> + <title>Catching an Exception</title> + <programlisting role="php"> +<![CDATA[ +<?php +try { + throw new Exception('Error'); +} catch (Exception $e) { + echo 'Caught exception: ', $e->getMessage(), "\n"; +} + +// Continue execution +echo "Hello World\n"; +]]> + </programlisting> + &example.outputs; + <screen> +<![CDATA[ +Caught exception: Error +Hello World +]]> + </screen> + </example> + + <simpara> + As of PHP 7.1.0, a &catch; block may specify a union of + <exceptionname>Throwable</exceptionname> subclasses that the block should handle + using the pipe (<literal>|</literal>) character. This is useful for when + different exceptions from different class hierarchies are handled the same. + </simpara> + <example> + <title>Catching a union of classes to handle</title> + <programlisting role="php"> +<![CDATA[ +<?php + +class MyException extends Exception { } + +class MyOtherException extends Exception { } + +class Test { + public function testing() { + try { + throw new MyException(); + } catch (MyException | MyOtherException $e) { + var_dump(get_class($e)); + } + } +} + +$foo = new Test; +$foo->testing(); +]]> + </programlisting> + &example.outputs; + <screen> +<![CDATA[ +string(11) "MyException" +]]> + </screen> + </example> + + <simpara> + Multiple &catch; blocks can be used to handle different classes of + <exceptionname>Throwable</exceptionname> errors in different ways. + Normal execution (when no error is thrown within the &try; block) will + continue after that last &catch; block defined in sequence. + </simpara> + <example> + <title>Multiple catch blocks</title> + <programlisting role="php" annotations="non-interactive"> +<![CDATA[ +<?php +try { + do_something_io_related(); +} catch (FileNotFoundException $e) { + // Only catch FileNotFoundException and do something in this case +} catch (MissingPermissionException $e) { + // Only catch MissingPermissionException and do something different in this case +} +]]> + </programlisting> + </example> + + <simpara> + <exceptionname>Throwable</exceptionname>s can be &throw;n (or re-thrown) within a &catch; block. + If nothing is thrown, the execution resumes as normal. + </simpara> + <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> + <caution> + <simpara> + Throwing an object inside a &catch; block will <emphasis>not</emphasis> + be caught by an adjacent &catch; block. + </simpara> + <example> + <title>Sequential catch blocks</title> + <programlisting role="php"> +<![CDATA[ +<?php + +class A extends Exception {} +class B extends Exception {} + +try { + throw new A; +} catch(A $e) { + throw new B; +} catch(B) { + echo 'Hello'; +} + +]]> + </programlisting> + &example.outputs.similar; + <screen> +<![CDATA[ +Fatal error: Uncaught B in /in/K8Tl9:9 +Stack trace: +#0 {main} + thrown in /in/K8Tl9 on line 9 +]]> + </screen> + </example> + </caution> + + <simpara> + As of PHP 8.0.0, the variable name for a caught + <exceptionname>Throwable</exceptionname> is optional. + If not specified, the &catch; block will still execute but will not + have access to the thrown object. + </simpara> + <example> + <title>Omitting the caught variable</title> + <simpara>Only permitted as of PHP 8.0.0.</simpara> + <programlisting role="php"> +<![CDATA[ +<?php + +class SpecificException extends Exception {} + +function test() { + throw new SpecificException('Oopsie'); +} + +try { + test(); +} catch (SpecificException) { + print "A SpecificException was thrown, but we don't care about the details."; +} +]]> + </programlisting> + &example.outputs; + <screen> +<![CDATA[ +A SpecificException was thrown, but we don't care about the details. +]]> + </screen> + </example> + </sect2> +</sect1> diff --git a/language/error-handling.xml b/language/error-handling.xml new file mode 100644 index 000000000000..2ff1549d27d3 --- /dev/null +++ b/language/error-handling.xml @@ -0,0 +1,357 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- $Revision$ --> +<chapter xml:id="language.error-handling" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" annotations="interactive"> + <title>Error Handling</title> + <note> + <simpara>See also the <exceptionname>Exception</exceptionname> class</simpara> + </note> + <simpara> + Errors are a normal part of the development and life cycle of an application. + As such PHP provides multiple ways to inform and deal with errors. + </simpara> + <para> + PHP has two main mechanisms for reporting errors: + <itemizedlist> + <listitem> + <simpara> + <exceptionname>Throwable</exceptionname> errors, which are further split into + <emphasis>programming</emphasis> errors via the <exceptionname>Error</exceptionname> + class hierarchy and <emphasis>recoverable</emphasis> errors via the + <exceptionname>Exception</exceptionname> class hierarchy. + </simpara> + </listitem> + <listitem> + <simpara> + Diagnostic errors which are classified into different + <link linkend="errorfunc.constants">severities</link>. + </simpara> + </listitem> + </itemizedlist> + </para> + + <sect1 xml:id="language.error-handling.throwable"> + <title><exceptionname>Throwable</exceptionname> errors</title> + <anchor xml:id="language.exceptions"/> + <simpara> + A <exceptionname>Throwable</exceptionname> error is an execution event which disrupts + the normal flow of instructions. When a <exceptionname>Throwable</exceptionname> error + is &throw;n, be that by the engine or manually, it will unwind the call stack + until it is caught by a &catch; block or the global scope is reached, in which + case the program is terminated with a fatal error. + All &finally; blocks it encounters along the way will be executed. + </simpara> + <simpara> + To throw a <exceptionname>Throwable</exceptionname> error from within PHP code, one + must use the &throw; keyword followed by an instance of the + <exceptionname>Error</exceptionname> or <exceptionname>Exception</exceptionname> class or + a subclass of one of them. + Trying to throw an object that is not will result in an + <exceptionname>Error</exceptionname> being thrown with the following message: + <literal>Cannot throw objects that do not implement Throwable</literal>. + </simpara> + <tip> + <simpara> + The <link linkend="intro.spl">Standard PHP Library (SPL)</link> provides + various <link linkend="spl.exceptions">built-in exceptions</link>. + And it's possible to create custom exceptions by + <link linkend="language.error-handling.throwable.extending">extending the + Exception class</link>. + </simpara> + </tip> + <simpara> + It is possible to handle a <exceptionname>Throwable</exceptionname> error within PHP + by surrounding the code susceptible to throw an error in a &try; block. + A &try; block must have at least one corresponding &catch; or &finally; block. + </simpara> + <note> + <simpara> + It is <emphasis>not</emphasis> recommended to catch <exceptionname>Error</exceptionname> + objects as those signal a programming error. + </simpara> + </note> + <warning> + <simpara> + <exceptionname>Throwable</exceptionname> objects cannot be cloned. + Attempting to <link linkend="language.oop5.cloning">clone</link> such an + object throws an <exceptionname>Error</exceptionname>, even if a subclass declares + its own <link linkend="object.clone">__clone()</link> method, with + the following message: + <literal>Trying to clone an uncloneable object of class Exception</literal>. + </simpara> + </warning> + + <sect2 xml:id="language.error-handling.throwable.user"> + <title><literal>Global exception handler</literal></title> + <simpara> + It's possible to add a handler for any uncaught + <exceptionname>Throwable</exceptionname> with + <function>set_exception_handler</function>. + This is similar to wrapping the entire code in a &try;-&catch; block, + except that execution does not resume afterwards: the script + terminates once the handler returns. + </simpara> + </sect2> + + <sect2 xml:id="language.error-handling.throwable.extending"> + <title>Extending Exceptions</title> + <simpara> + A user-defined exception can be defined by extending the built-in + <exceptionname>Exception</exceptionname> class. + To see which methods and properties are accessible within a child class + derived from <exceptionname>Exception</exceptionname> visit its page. + </simpara> + <simpara> + If a class extends the built-in <exceptionname>Exception</exceptionname> class and + re-defines the <link linkend="language.oop5.decon">constructor</link>, + it is highly recommended that it also call <code>parent::__construct()</code> + to ensure all available data has been properly assigned. + The <link linkend="object.tostring">__toString()</link> method can be overridden + to provide a custom output when the object is used as a string. + </simpara> + <example> + <title>Extending <exceptionname>Exception</exceptionname></title> + <programlisting role="php"> +<![CDATA[ +<?php +class CustomException extends Exception +{ + // Redefine the constructor so message isn't optional + public function __construct($message, $code = 0, ?Throwable $previous = null) { + // some code + + // Ensure 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"; + } +} + +try { + throw new CustomException("Something happened", 5); +} catch (CustomException $e) { + echo "Caught custom exception\n", $e; + $e->customFunction(); +} +]]> + </programlisting> + &example.outputs; + <screen> +<![CDATA[ +Caught custom exception +CustomException: [5]: Something happened +A custom function for this type of exception +]]> + </screen> + </example> + </sect2> + + <sect2 xml:id="language.error-handling.throwable.hierarchy"> + <title><exceptionname>Throwable</exceptionname> hierarchy</title> + + <itemizedlist> + <listitem> + <simpara><exceptionname>Throwable</exceptionname></simpara> + <itemizedlist> + <listitem> + <simpara><exceptionname>Error</exceptionname></simpara> + <itemizedlist> + <listitem> + <simpara><exceptionname>ArithmeticError</exceptionname></simpara> + <itemizedlist> + <listitem> + <simpara><exceptionname>DivisionByZeroError</exceptionname></simpara> + </listitem> + </itemizedlist> + </listitem> + <listitem> + <simpara><exceptionname>AssertionError</exceptionname></simpara> + </listitem> + <listitem> + <simpara><exceptionname>CompileError</exceptionname></simpara> + <itemizedlist> + <listitem> + <simpara><exceptionname>ParseError</exceptionname></simpara> + </listitem> + </itemizedlist> + </listitem> + <listitem> + <simpara><exceptionname>TypeError</exceptionname></simpara> + <itemizedlist> + <listitem> + <simpara><exceptionname>ArgumentCountError</exceptionname></simpara> + </listitem> + </itemizedlist> + </listitem> + <listitem> + <simpara><exceptionname>ValueError</exceptionname></simpara> + </listitem> + <listitem> + <simpara><exceptionname>UnhandledMatchError</exceptionname></simpara> + </listitem> + <listitem> + <simpara><exceptionname>FiberError</exceptionname></simpara> + </listitem> + </itemizedlist> + </listitem> + <listitem> + <simpara><exceptionname>Exception</exceptionname></simpara> + </listitem> + </itemizedlist> + </listitem> + </itemizedlist> + + <simpara> + The <exceptionname>Exception</exceptionname> class has many subclasses, + among them the <link linkend="spl.exceptions">SPL exceptions</link> and + those defined by extensions. + </simpara> + </sect2> + </sect1> + + <sect1 xml:id="language.error-handling.diagnostic"> + <title>Diagnostic errors</title> + <simpara> + Diagnostic errors, also known as traditional errors, are used to signal a + number of different conditions, and can be displayed and/or logged as required. + By default PHP will report all diagnostic errors. (Prior to PHP 8.0, + <constant>E_NOTICE</constant> and <constant>E_DEPRECATED</constant> + diagnostics were not reported by default.) + </simpara> + <simpara> + In contrast to <exceptionname>Throwable</exceptionname> errors, most diagnostic + errors do <emphasis>not</emphasis> disrupt the normal flow of execution. + Fatal diagnostics, such as <constant>E_ERROR</constant>, terminate the script. + </simpara> + <simpara> + Which diagnostics are reported and which are ignored is controlled by the + <link linkend="ini.error-reporting"><parameter>error_reporting</parameter></link> + &php.ini; directive, or at runtime by calling <function>error_reporting</function>. + It is strongly recommended that the configuration directive be set, + as some errors can occur before execution of your script begins. + </simpara> + <note> + <simpara> + In a development environment, + <link linkend="ini.error-reporting"><parameter>error_reporting</parameter></link> + should always be set to <constant>E_ALL</constant> to be aware of and fix + issues raised by PHP. + However, in production the level of verbosity could be reduced to + <code>E_ALL &amp; ~E_NOTICE &amp; ~E_DEPRECATED</code>, but in many cases + <constant>E_ALL</constant> is still appropriate, as it may provide early + warning of potential issues. + </simpara> + </note> + + <simpara> + What happens to the diagnostics depends on two further &php.ini; directives. + <link linkend="ini.display-errors"><parameter>display_errors</parameter></link> + controls whether the diagnostic is shown as part of the script's output. + This should always be disabled in a production environment, as it can include + confidential information such as database passwords, but is often useful to + enable in development, as it ensures immediate reporting of issues. + </simpara> + + <simpara> + In addition to displaying errors, PHP can log diagnostics when the + <link linkend="ini.log-errors"><parameter>log_errors</parameter></link> + directive is enabled. This will log any diagnostic to the file or syslog + defined by + <link linkend="ini.error-log"><parameter>error_log</parameter></link>. + This can be extremely useful in a production environment, as diagnostics are + logged when they occur and can then generate reports based on those logs. + </simpara> + <simpara> + Individual diagnostics can be suppressed using the + <literal linkend="language.operators.errorcontrol">@</literal> operator. + </simpara> + + <warning> + <simpara> + Prior to PHP 8.0.0 it was possible to suppress critical diagnostics that + would terminate the execution of the PHP script. + </simpara> + </warning> + + <note> + <simpara> + Diagnostics can be added, removed, have their severity altered or be + elevated to a <exceptionname>Throwable</exceptionname> error in between PHP versions. + </simpara> + </note> + + <sect2 xml:id="language.error-handling.diagnostic.user"> + <title>User defined diagnostic handler</title> + + <simpara> + If PHP's default diagnostic handling is inadequate, + it is possible to override the default diagnostic handler with a custom one + which is set using <function>set_error_handler</function>. + Some diagnostics, such as <constant>E_ERROR</constant> and + <constant>E_PARSE</constant>, cannot be handled this way (see + <function>set_error_handler</function> for the full list). + The others can be handled in various ways. For example, this can be used to show a custom + error page to the user and then report more directly than via a log, such + as by sending an e-mail. + </simpara> + + <simpara> + Another typical usage is to elevate diagnostic errors to exceptions with + <link linkend="class.errorexception">ErrorException</link>. + </simpara> + <example> + <title>Elevating diagnostic errors to exceptions</title> + <programlisting role="php"> +<![CDATA[ +<?php +function exceptions_error_handler($severity, $message, $filename, $lineno) { + if (error_reporting() & $severity) { + throw new ErrorException($message, 0, $severity, $filename, $lineno); + } +} + +set_error_handler('exceptions_error_handler'); +]]> + </programlisting> + <note> + <simpara> + It is important to verify that the severity is included in the current + list of reportable diagnostics, otherwise the + <literal linkend="language.operators.errorcontrol">@</literal> operator + will be broken, as an exception will be thrown for a suppressed diagnostic. + <!-- TODO: add an example? --> + </simpara> + </note> + </example> + </sect2> + + <sect2 role="changelog"> + &reftitle.changelog; + <informaltable> + <tgroup cols="2"> + <thead> + <row> + <entry>&Version;</entry> + <entry>&Description;</entry> + </row> + </thead> + <tbody> + <row> + <entry>8.5.0</entry> + <entry> + Fatal errors (such as an exceeded maximum execution time) now include + a stack trace in their error message. + </entry> + </row> + </tbody> + </tgroup> + </informaltable> + </sect2> + </sect1> +</chapter> diff --git a/language/errors.xml b/language/errors.xml deleted file mode 100644 index 0c5edd64cf82..000000000000 --- a/language/errors.xml +++ /dev/null @@ -1,40 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- $Revision$ --> -<chapter xml:id="language.errors" xmlns="http://docbook.org/ns/docbook"> - <title>Errors</title> - - <sect1 annotations="chunk:false" xml:id="language.errors.intro"> - <title>Introduction</title> - - <para> - Sadly, no matter how careful we are when writing our code, errors are a - fact of life. PHP will report errors, warnings and notices for many common - coding and runtime problems, and knowing how to detect and handle these - errors will make debugging much easier. - </para> - </sect1> - - &language.errors.basics; - &language.errors.php7; -</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 ---> diff --git a/language/errors/basics.xml b/language/errors/basics.xml deleted file mode 100644 index 5b31f247e8d7..000000000000 --- a/language/errors/basics.xml +++ /dev/null @@ -1,124 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- $Revision$ --> - -<sect1 xml:id="language.errors.basics" xmlns="http://docbook.org/ns/docbook"> - <title>Basics</title> - - <para> - PHP reports errors in response to a number of internal error conditions. - These may be used to signal a number of different conditions, and can be - displayed and/or logged as required. - </para> - - <para> - Every error that PHP generates includes a type. A - <link linkend="errorfunc.constants">list of these error types</link> is available, - along with a short description of their behaviour and how they can be - caused. - </para> - - <sect2 xml:id="language.errors.basics.handling"> - <title>Handling errors with PHP</title> - - <para> - If no error handler is set, then PHP will handle any errors that occur - according to its configuration. Which errors are reported and which are - ignored is controlled by the - <link linkend="ini.error-reporting"><parameter>error_reporting</parameter></link> - php.ini directive, or at runtime by calling - <function>error_reporting</function>. It is strongly recommended that the - configuration directive be set, however, as some errors can occur before - execution of your script begins. - </para> - - <para> - In a development environment, you should always set - <link linkend="ini.error-reporting"><parameter>error_reporting</parameter></link> - to <constant>E_ALL</constant>, as you need to be aware of and fix the - issues raised by PHP. In production, you may wish to set this to a less - verbose level such as - <code>E_ALL &amp; ~E_NOTICE &amp; ~E_DEPRECATED</code>, but - in many cases <constant>E_ALL</constant> is also appropriate, as it may - provide early warning of potential issues. - </para> - - <para> - What PHP does with these errors depends on two further php.ini directives. - <link linkend="ini.display-errors"><parameter>display_errors</parameter></link> - controls whether the error is shown as part of the script's output. This - should always be disabled in a production environment, as it can include - confidential information such as database passwords, but is often useful to - enable in development, as it ensures immediate reporting of issues. - </para> - - <para> - In addition to displaying errors, PHP can log errors when the - <link linkend="ini.log-errors"><parameter>log_errors</parameter></link> - directive is enabled. This will log any errors to the file or syslog - defined by - <link linkend="ini.error-log"><parameter>error_log</parameter></link>. This - can be extremely useful in a production environment, as you can log errors - that occur and then generate reports based on those errors. - </para> - </sect2> - - <sect2 xml:id="language.errors.basics.user"> - <title>User error handlers</title> - - <para> - If PHP's default error handling is inadequate, you can also handle many - types of error with your own custom error handler by installing it with - <function>set_error_handler</function>. While some error types cannot be - handled this way, those that can be handled can then be handled in the way - that your script sees fit: for example, this can be used to show a custom - error page to the user and then report more directly than via a log, such - as by sending an e-mail. - </para> - </sect2> - - <sect2 role="changelog"> - &reftitle.changelog; - <informaltable> - <tgroup cols="2"> - <thead> - <row> - <entry>&Version;</entry> - <entry>&Description;</entry> - </row> - </thead> - <tbody> - <row> - <entry>8.5.0</entry> - <entry> - Fatal errors (such as an exceeded maximum execution time) now include - a stack trace in their error message. - </entry> - </row> - </tbody> - </tgroup> - </informaltable> - </sect2> - -</sect1> - -<!-- 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 ---> - diff --git a/language/errors/php7.xml b/language/errors/php7.xml deleted file mode 100644 index 55400297825c..000000000000 --- a/language/errors/php7.xml +++ /dev/null @@ -1,117 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- $Revision$ --> - -<sect1 xml:id="language.errors.php7" xmlns="http://docbook.org/ns/docbook"> - <title>Errors in PHP 7</title> - - <para> - PHP 7 changes how most errors are reported by PHP. Instead of reporting - errors through the traditional error reporting mechanism used by PHP 5, most - errors are now reported by throwing <classname>Error</classname> exceptions. - </para> - - <para> - As with normal exceptions, these <classname>Error</classname> exceptions - will bubble up until they reach the first matching - <link linkend="language.exceptions.catch"><literal>catch</literal></link> - block. If there are no matching blocks, then any default exception handler - installed with <function>set_exception_handler</function> will be called, - and if there is no default exception handler, then the exception will be - converted to a fatal error and will be handled like a traditional error. - </para> - - <para> - As the <classname>Error</classname> hierarchy does not inherit from - <classname>Exception</classname>, code that uses - <code>catch (Exception $e) { ... }</code> blocks to handle uncaught - exceptions in PHP 5 will find that these <classname>Error</classname>s are - not caught by these blocks. Either a <code>catch (Error $e) { ... }</code> - block or a <function>set_exception_handler</function> handler is required. - </para> - - <sect2 xml:id="language.errors.php7.hierarchy"> - <title><classname>Error</classname> hierarchy</title> - - <itemizedlist> - <listitem> - <simpara><classname>Throwable</classname></simpara> - <itemizedlist> - <listitem> - <simpara><classname>Error</classname></simpara> - <itemizedlist> - <listitem> - <simpara><classname>ArithmeticError</classname></simpara> - <itemizedlist> - <listitem> - <simpara><classname>DivisionByZeroError</classname></simpara> - </listitem> - </itemizedlist> - </listitem> - <listitem> - <simpara><classname>AssertionError</classname></simpara> - </listitem> - <listitem> - <simpara><classname>CompileError</classname></simpara> - <itemizedlist> - <listitem> - <simpara><classname>ParseError</classname></simpara> - </listitem> - </itemizedlist> - </listitem> - <listitem> - <simpara><classname>TypeError</classname></simpara> - <itemizedlist> - <listitem> - <simpara><classname>ArgumentCountError</classname></simpara> - </listitem> - </itemizedlist> - </listitem> - <listitem> - <simpara><classname>ValueError</classname></simpara> - </listitem> - <listitem> - <simpara><classname>UnhandledMatchError</classname></simpara> - </listitem> - <listitem> - <simpara><classname>FiberError</classname></simpara> - </listitem> - <listitem> - <simpara><classname>RequestParseBodyException</classname></simpara> - </listitem> - </itemizedlist> - </listitem> - <listitem> - <simpara><classname>Exception</classname></simpara> - <itemizedlist> - <listitem> - <simpara>...</simpara> - </listitem> - </itemizedlist> - </listitem> - </itemizedlist> - </listitem> - </itemizedlist> - </sect2> -</sect1> - -<!-- 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 ---> - diff --git a/language/exceptions.xml b/language/exceptions.xml deleted file mode 100644 index c284e26c36d5..000000000000 --- a/language/exceptions.xml +++ /dev/null @@ -1,591 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- $Revision$ --> -<chapter xml:id="language.exceptions" xmlns="http://docbook.org/ns/docbook" annotations="interactive"> - <title>Exceptions</title> - <note> - <simpara>See also the <exceptionname>Exception</exceptionname> class</simpara> - </note> - <para> - PHP 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> - If an exception is thrown and its current function scope has no &catch; - block, the exception will "bubble up" the call stack to the calling - function until it finds a matching &catch; block. All &finally; blocks it encounters - along the way will be executed. If the call stack is unwound all the way to the - global scope without encountering a matching &catch; block, the program will - terminate with a fatal error unless a global exception handler has been set. - </para> - <para> - The thrown object must be an &instanceof; <interfacename>Throwable</interfacename>. - Trying to throw an object that is not will result in a PHP Fatal Error. - </para> - <para> - As of PHP 8.0.0, the &throw; keyword is an expression and may be used in any expression - context. In prior versions it was a statement and was required to be on its own line. - </para> - - <sect1 annotations="chunk:false" xml:id="language.exceptions.catch"> - <title><literal>catch</literal></title> - <para> - A &catch; block defines how to respond to a thrown exception. A &catch; - block defines one or more types of exception or error it can handle, and - optionally a variable to which to assign the exception. (The variable was - required prior to PHP 8.0.0.) The first &catch; block a thrown exception - or error encounters that matches the type of the thrown object will handle - the object. - </para> - <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. If not, - execution will continue after the &catch; block that was triggered. - </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> - <para> - As of PHP 7.1.0, a &catch; block may specify multiple exceptions - using the pipe (<literal>|</literal>) character. This is useful for when - different exceptions from different class hierarchies are handled the - same. - </para> - <para> - As of PHP 8.0.0, the variable name for a caught exception is optional. - If not specified, the &catch; block will still execute but will not - have access to the thrown object. - </para> - </sect1> - - <sect1 annotations="chunk:false" xml:id="language.exceptions.finally"> - <title><literal>finally</literal></title> - <para> - 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> - <para> - One notable interaction is between the &finally; block and a &return; statement. - If a &return; statement is encountered inside either the &try; or the &catch; blocks, - the &finally; block will still be executed. Moreover, the &return; statement is - evaluated when encountered, but the result will be returned after the &finally; block - is executed. Additionally, if the &finally; block also contains a &return; statement, - the value from the &finally; block is returned. - </para> - <para> - Another notable interaction is between an exception thrown from within a &try; block, - and an exception thrown from within a &finally; block. If both blocks throw an exception, - then the exception thrown from the &finally; block will be the one that is propagated, - and the exception thrown from the &try; block will be used as its previous exception. - </para> - </sect1> - - <sect1 annotations="chunk:false" xml:id="language.exceptions.exception-handler"> - <title>Global exception handler</title> - <para> - If an exception is allowed to bubble up to the global scope, it may be caught - by a global exception handler if set. The <function>set_exception_handler</function> - function can set a function that will be called in place of a &catch; block if no - other block is invoked. The effect is essentially the same as if the entire program - were wrapped in a &try;-&catch; block with that function as the &catch;. - </para> - </sect1> - - <sect1 annotations="chunk:false" 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 easily translated to - exceptions with <link linkend="class.errorexception">ErrorException</link>. - This technique only works with non-fatal errors, however. - </para> - <example> - <title>Converting error reporting to exceptions</title> - <programlisting role="php" annotations="non-interactive"> -<![CDATA[ -<?php -function exceptions_error_handler($severity, $message, $filename, $lineno) { - throw new ErrorException($message, 0, $severity, $filename, $lineno); -} - -set_error_handler('exceptions_error_handler'); -]]> - </programlisting> - </example> - </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> - </sect1> - - <sect1 annotations="chunk:false" 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 &finally; 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>Interaction between the &finally; block and &return;</title> - <programlisting role="php"> -<![CDATA[ -<?php - -function test() { - try { - throw new Exception('foo'); - } catch (Exception $e) { - return 'catch'; - } finally { - return 'finally'; - } -} - -echo test(); -]]> - </programlisting> - &example.outputs; - <screen> -<![CDATA[ -finally -]]> - </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> - <example> - <title>Multi catch exception handling</title> - <programlisting role="php"> -<![CDATA[ -<?php - -class MyException extends Exception { } - -class MyOtherException extends Exception { } - -class Test { - public function testing() { - try { - throw new MyException(); - } catch (MyException | MyOtherException $e) { - var_dump(get_class($e)); - } - } -} - -$foo = new Test; -$foo->testing(); -]]> - </programlisting> - &example.outputs; - <screen> -<![CDATA[ -string(11) "MyException" -]]> - </screen> - </example> - <example> - <title>Omitting the caught variable</title> - <para>Only permitted in PHP 8.0.0 and later.</para> - <programlisting role="php"> -<![CDATA[ -<?php - -class SpecificException extends Exception {} - -function test() { - throw new SpecificException('Oopsie'); -} - -try { - test(); -} catch (SpecificException) { - print "A SpecificException was thrown, but we don't care about the details."; -} -]]> - </programlisting> - &example.outputs; - <screen> -<![CDATA[ -A SpecificException was thrown, but we don't care about the details. -]]> - </screen> - </example> - <example> - <title>Throw as an expression</title> - <para>Only permitted in PHP 8.0.0 and later.</para> - <programlisting role="php"> -<![CDATA[ -<?php - -function test() { - do_something_risky() or throw new Exception('It did not work'); -} - -function do_something_risky() { - return false; // Simulate failure -} - -try { - test(); -} catch (Exception $e) { - print $e->getMessage(); -} -]]> - </programlisting> - &example.outputs; - <screen> -<![CDATA[ -It did not work -]]> - </screen> - </example> - <example> - <title>Exception in try and in finally</title> - <programlisting role="php"> -<![CDATA[ -<?php - -try { - try { - throw new Exception(message: 'Third', previous: new Exception('Fourth')); - } finally { - throw new Exception(message: 'First', previous: new Exception('Second')); - } -} catch (Exception $e) { - var_dump( - $e->getMessage(), - $e->getPrevious()->getMessage(), - $e->getPrevious()->getPrevious()->getMessage(), - $e->getPrevious()->getPrevious()->getPrevious()->getMessage(), - ); -} -]]> - </programlisting> - &example.outputs; - <screen> -<![CDATA[ -string(5) "First" -string(6) "Second" -string(5) "Third" -string(6) "Fourth" -]]> - </screen> - </example> - </sect1> - - <sect1 xml:id="language.exceptions.extending"> - <title>Extending Exceptions</title> - <para> - A User defined Exception class can be defined by extending the built-in - <exceptionname>Exception</exceptionname> 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" annotations="non-interactive"> - <![CDATA[ -<?php -class Exception implements Throwable -{ - protected $message = ''; // 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 = '', $code = 0, ?Throwable $previous = null); - - 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 - - // Overridable - public function __toString(); // formatted string for display -} -]]> - </programlisting> - </example> - <para> - If a class extends the built-in <exceptionname>Exception</exceptionname> 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> - <simpara> - Exceptions cannot be cloned. Attempting to <link - linkend="language.oop5.cloning">clone</link> an exception throws an - <exceptionname>Error</exceptionname>, even if a subclass declares its own - <link linkend="object.clone">__clone()</link> method. - </simpara> - </note> - <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, ?Throwable $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; - } - } -} - - -echo "# Example 1\n"; -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\n"; -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\n"; -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\n"; -try { - $o = new TestException(); -} catch (Exception $e) { // Skipped, no exception - echo "Default Exception caught\n", $e; -} - -// Continue execution -var_dump($o); // TestException -]]> - </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:"~/.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 ---> diff --git a/language/oop5/basic.xml b/language/oop5/basic.xml index ea87be554544..bdf64c7d676c 100644 --- a/language/oop5/basic.xml +++ b/language/oop5/basic.xml @@ -197,14 +197,14 @@ readonly class Foo <sect2 xml:id="language.oop5.basic.new"> <title>new</title> - <para> + <simpara> To create an instance of a class, the <literal>new</literal> keyword must be used. An object will always be created unless the object has a <link linkend="language.oop5.decon">constructor</link> defined that throws an - <link linkend="language.exceptions">exception</link> on error. Classes + <exceptionname>Exception</exceptionname> on error. Classes should be defined before instantiation (and in some cases this is a requirement). - </para> + </simpara> <para> If a variable containing a <type>string</type> with the name of a class is used with <literal>new</literal>, a new instance of that class will be created. If diff --git a/language/oop5/changelog.xml b/language/oop5/changelog.xml index 9580aecbd184..bccee0a60328 100644 --- a/language/oop5/changelog.xml +++ b/language/oop5/changelog.xml @@ -213,7 +213,7 @@ <row> <entry>5.5.0</entry> <entry> - Added: <link linkend="language.exceptions">finally</link> to handle exceptions. + Added: <link linkend="control-structures.finally">finally</link> to handle exceptions. </entry> </row> <row> @@ -271,9 +271,9 @@ <entry> Changed: Prior to 5.3.0, exceptions thrown in the <function>__autoload</function> function could not be - caught in the <link linkend="language.exceptions">catch</link> block, and + caught in the <link linkend="control-structures.catch">catch</link> block, and would result in a fatal error. Exceptions now thrown in the __autoload function - can be caught in the <link linkend="language.exceptions">catch</link> block, with + can be caught in the <link linkend="control-structures.catch">catch</link> block, with one provision. If throwing a custom exception, then the custom exception class must be available. The __autoload function may be used recursively to autoload the custom exception class. diff --git a/language/operators/precedence.xml b/language/operators/precedence.xml index 9d4f02925ef5..2dfbdd8963a3 100644 --- a/language/operators/precedence.xml +++ b/language/operators/precedence.xml @@ -320,7 +320,7 @@ <entry>(n/a)</entry> <entry><literal>throw</literal></entry> <entry> - <link linkend="language.exceptions">throw</link> + <link linkend="control-structures.throw">throw</link> </entry> </row> </tbody> diff --git a/language/predefined/exceptions.xml b/language/predefined/exceptions.xml index 14a3f914d56c..c963e3d2a0e0 100644 --- a/language/predefined/exceptions.xml +++ b/language/predefined/exceptions.xml @@ -15,7 +15,7 @@ &language.predefined.closedgeneratorexception; <!-- If this is updated, you should also update the hierarchy in - language/errors/php7.xml. --> + language/error-handling.xml. --> &language.predefined.error; &language.predefined.argumentcounterror; &language.predefined.arithmeticerror; diff --git a/manual.xml b/manual.xml index 84c6986aa404..f393b9f67120 100644 --- a/manual.xml +++ b/manual.xml @@ -52,8 +52,7 @@ &language.oop5; &language.namespaces; &language.enumerations; - &language.errors; - &language.exceptions; + &language.error-handling; &language.fibers; &language.generators; &language.attributes; diff --git a/reference/dom/domexception.xml b/reference/dom/domexception.xml index bcea4a042ff6..e6488c45735a 100644 --- a/reference/dom/domexception.xml +++ b/reference/dom/domexception.xml @@ -25,9 +25,9 @@ FIXME: Remove me once you perform substitutions This class is aliased as <classname>Dom\Exception</classname> in the Dom namespace. </simpara> - <para> - See also <xref linkend="language.exceptions"/>. - </para> + <simpara> + See also <xref linkend="language.error-handling.throwable"/>. + </simpara> </section> <!-- }}} --> diff --git a/reference/errorfunc/functions/get-exception-handler.xml b/reference/errorfunc/functions/get-exception-handler.xml index 919e03687b31..a24d27f44649 100644 --- a/reference/errorfunc/functions/get-exception-handler.xml +++ b/reference/errorfunc/functions/get-exception-handler.xml @@ -91,7 +91,7 @@ if (!function_exists('get_exception_handler')) { <member><function>restore_exception_handler</function></member> <member><function>restore_error_handler</function></member> <member><function>error_reporting</function></member> - <member><link linkend="language.exceptions">Exceptions</link></member> + <member><link linkend="language.error-handling.throwable">Exceptions</link></member> </simplelist> </refsect1> </refentry> diff --git a/reference/errorfunc/functions/set-exception-handler.xml b/reference/errorfunc/functions/set-exception-handler.xml index df06f4462c14..107f531f7c2a 100644 --- a/reference/errorfunc/functions/set-exception-handler.xml +++ b/reference/errorfunc/functions/set-exception-handler.xml @@ -149,7 +149,7 @@ echo "Not Executed\n"; <member><function>restore_exception_handler</function></member> <member><function>restore_error_handler</function></member> <member><function>error_reporting</function></member> - <member><link linkend="language.exceptions">Exceptions</link></member> + <member><link linkend="language.error-handling.throwable">Exceptions</link></member> </simplelist> </refsect1><!-- }}} --> diff --git a/reference/pdo/connections.xml b/reference/pdo/connections.xml index 6602616cc3b4..3bfb98ae4661 100644 --- a/reference/pdo/connections.xml +++ b/reference/pdo/connections.xml @@ -44,8 +44,8 @@ try { </example> </para> <warning> - <para> - Just like any other <link linkend="language.exceptions">exception</link>, + <simpara> + Just like any other <link linkend="language.error-handling.throwable">exception</link>, <classname>PDOException</classname> could be caught either explicitly, via a &catch; statement, or implicitly via <function>set_exception_handler</function>. Otherwise, the default behaviour of converting an uncaught exception to a @@ -54,7 +54,7 @@ try { As such, the &php.ini; option <link linkend="ini.display-errors"><literal>display_errors</literal></link> should be set to <literal>0</literal> on a production server. - </para> + </simpara> </warning> <para> Upon successful connection to the database, an instance of the PDO class diff --git a/reference/pdo/error-handling.xml b/reference/pdo/error-handling.xml index 83bb4c22d0fd..64e0e72c867c 100644 --- a/reference/pdo/error-handling.xml +++ b/reference/pdo/error-handling.xml @@ -57,10 +57,10 @@ with less code/nesting than by running in silent mode and explicitly checking the return value of each database call. </para> - <para> - See <link linkend="language.exceptions">Exceptions</link> for more - information about Exceptions in PHP. - </para> + <simpara> + See <xref linkend="language.error-handling.throwable"/> for more + information about handling Exceptions in PHP. + </simpara> </listitem> </itemizedlist> <para> diff --git a/reference/pdo/pdoexception.xml b/reference/pdo/pdoexception.xml index 1d702df4c231..1a3fefe4bb62 100644 --- a/reference/pdo/pdoexception.xml +++ b/reference/pdo/pdoexception.xml @@ -8,12 +8,13 @@ <section xml:id="pdoexception.intro"> &reftitle.intro; - <para> + <simpara> Represents an error raised by PDO. You should not throw a <classname>PDOException</classname> from your own code. - See <link linkend="language.exceptions">Exceptions</link> for more - information about Exceptions in PHP. - </para> + </simpara> + <simpara> + See also <xref linkend="language.error-handling.throwable"/>. + </simpara> </section> <section xml:id="pdoexception.synopsis"> diff --git a/reference/snmp/snmpexception.xml b/reference/snmp/snmpexception.xml index 8f91ea641c60..36834097cae9 100644 --- a/reference/snmp/snmpexception.xml +++ b/reference/snmp/snmpexception.xml @@ -11,7 +11,7 @@ <simpara> Represents an error raised by SNMP. You should not throw a <classname>SNMPException</classname> from your own code. - See <link linkend="language.exceptions">Exceptions</link> for more + See <link linkend="language.error-handling.throwable">Exceptions</link> for more information about Exceptions in PHP. </simpara> </section>

« previous php.doc.cvs (#23813) next »