diff --git a/appendices/migration70/incompatible/error-handling.xml b/appendices/migration70/incompatible/error-handling.xml index 37e9a31525b8..8da24cfb0ffa 100644 --- a/appendices/migration70/incompatible/error-handling.xml +++ b/appendices/migration70/incompatible/error-handling.xml @@ -18,8 +18,8 @@ - A fuller description of how errors operate in PHP 7 can be found - on the PHP 7 errors page. This + A more complete description of how errors operate in PHP 7 can be found + on the PHP 7 errors page. This migration guide will merely enumerate the changes that affect backward compatibility. diff --git a/appendices/tokens.xml b/appendices/tokens.xml index 4294cbc1e38b..a044945ea421 100644 --- a/appendices/tokens.xml +++ b/appendices/tokens.xml @@ -134,7 +134,7 @@ defined('T_FN') || define('T_FN', 10001); T_CATCH catch - + T_CLASS @@ -387,7 +387,7 @@ defined('T_FN') || define('T_FN', 10001); T_FINALLY finally - + T_FN @@ -845,7 +845,7 @@ defined('T_FN') || define('T_FN', 10001); T_THROW throw - + T_TRAIT @@ -860,7 +860,7 @@ defined('T_FN') || define('T_FN', 10001); T_TRY try - + T_UNSET diff --git a/language/control-structures.xml b/language/control-structures.xml index 8adff8a75691..683b2135a644 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; diff --git a/language/control-structures/finally.xml b/language/control-structures/finally.xml new file mode 100644 index 000000000000..e874ba8dc08e --- /dev/null +++ b/language/control-structures/finally.xml @@ -0,0 +1,445 @@ + + + finally + + + A &finally; block may 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, + a Throwable error hasn't been caught or is rethrown. + It will be executed prior to resuming the normal execution flow. + The only exception to this rule is when a call to exit + is performed. + + + <classname>Throwable</classname> error handling with a &finally; block + +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"; +]]> + + &example.outputs.8; + + + + + + + When the call stack is unwound after a Throwable 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 + Throwable error is not caught by an adjacent + &catch; block. + + + All &finally; block will be executed + + + + &example.outputs; + + + + + + + Interaction between a &finally; block and a &return; statement + + 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. + + + Interaction between &return; in &finally; block and a previous &return; + + + + &example.outputs; + + + + + + Interaction between the &finally; block and &return; + + + + &example.outputs; + + + + + + + + + Behaviour of a &finally; block in a + <link linkend="language.generators">Generator</link> + + + + If during the traversal of a generator a Throwable + error is thrown, the &finally; within the generator will be executed, + as it is the previous element of the call stack. + + + + &finally; block being run when an <classname>Exception</classname> + has been thrown + + + + + &example.outputs.similar; + + + + + + + It is possible to &yield; within a &finally; block but if a + Throwable error occurs and is not caught within + the &foreach; a Cannot yield from finally in a force-closed + generator Error is thrown. + + + + Error when &yield;ing in &finally; block when an <classname>Exception</classname> + has been thrown + + + + + &example.outputs.similar; + + + + + + + + Interaction between a &finally; block and a call to <function>exit</function> + + When exit is called within a &try; or a &catch; block + all &finally; blocks are skipped. + + + Interaction between &finally; block and <function>exit</function> called in &try; block + + + + &example.outputs; + + + + + + Interaction between &finally; block and <function>exit</function> called in &catch; block + + + + &example.outputs; + + + + + + All &finally; blocks are skipped when <function>exit</function> is called + + + + &example.outputs; + + + + + + + When exit is called within a &finally; block, + all other outer &finally; blocks are skipped as per the above behaviour. + + + Skipping outer &finally; block by calling <function>exit</function> + + + + &example.outputs; + + + + + + + Edge case of calling <function>exit</function> in a &foreach; over a generator + + This one edge case behaviour is highly dependent on which version of PHP + the code is executed. + + + + + + + + Output of the above example prior to PHP 7.1.13, in PHP 7.2.0 and 7.2.1, + and as of PHP 8.0.0 + + + + + + Output of the above example as of PHP 7.1.14, and prior to PHP 8.0.0, + and as of PHP 8.0.0 + + + + + + + + diff --git a/language/control-structures/throw.xml b/language/control-structures/throw.xml new file mode 100644 index 000000000000..86b165de96a3 --- /dev/null +++ b/language/control-structures/throw.xml @@ -0,0 +1,118 @@ + + + throw + + + The &throw; keyword is an expression, and may be used in any expression context, + which takes an instance of a Throwable object as an + argument. + + + + Prior to PHP 8.0, the &throw; keyword was a statement and not an expression. + + + + Attempting to &throw; a non-Throwable object will + throw an Error. + + + Throwing a non-<classname>Throwable</classname> object + + + + &example.outputs.similar; + + + + + + + + After using &throw; the normal flow of execution is halted and the call stack + is unwound until the global scope is reached and terminates the program with + a fatal error containing the stack trace indicating where the + Throwable object has been thrown. + + + Throwing an Exception in the global scope + + + + &example.outputs.similar; + + + + + + Throwing an Exception in a function + + + + &example.outputs.similar; + + + + + + + As &throw; is an expression it can be used to branch out on the result + of another expression if its value is inappropriate. + + + Using throw as an expression + Only permitted in PHP 8.0.0 and later. + + + + + + + It is possible to handle a thrown Throwable by using + a try-catch block. + See the error handling + section for more information. + + diff --git a/language/control-structures/try-catch.xml b/language/control-structures/try-catch.xml new file mode 100644 index 000000000000..77b9df711e8d --- /dev/null +++ b/language/control-structures/try-catch.xml @@ -0,0 +1,240 @@ + + + try-catch blocks + + try + + + A &try; block delimits a segment of code which might &throw; + a Throwable error which one wants to possibly handle. + A &try; block must have at least one corresponding + &catch; or &finally; block. + + + + When a Throwable 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 as usual. + + + + It's possible to add a handler for any uncaught + Throwable with + set_exception_handler. + This is similar to wrapping the entire code in a &try;-&catch; block. + + + + + catch + + + A &catch; block defines how to respond to a thrown Throwable error. + A &catch; block defines one or more subclasses of Throwable + (most commonly Exception) it can handle, and + optionally a variable to which to assign the exception. + + + + Prior to PHP 8.0.0, the variable in which to assign the + Throwable object was mandatory. + + + + The first &catch; block a thrown Throwable encounters + that matches the class of the thrown object will handle the error before + resuming normal execution after the &catch; block. + + + Catching an Exception + +getMessage(), "\n"; +} + +// Continue execution +echo "Hello World\n"; +?> +]]> + + &example.outputs; + + + + + + + As of PHP 7.1.0, a &catch; block may specify a union of + Throwable subclasses that the block should handle + using the pipe (|) character. This is useful for when + different exceptions from different class hierarchies are handled the same. + + + Catching a union of classes to handle + + testing(); + +?> +]]> + + &example.outputs; + + + + + + + Multiple &catch; blocks can be used to handle different classes of + Throwable 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. + + + Multiple catch blocks + + + + + + + Throwables can be &throw;n (or re-thrown) within a &catch; block. + Otherwise, execution will continue after the &catch; block that was triggered. + + + Nested Exception + +getMessage()); + } + } +} + +$foo = new Test; +$foo->testing(); + +?> +]]> + + &example.outputs; + + + + + + + Throwing an object withing a &catch; block will not + be caught by an adjacent &catch; block. + + + Sequential catch blocks + + + + &example.outputs.similar; + + + + + + + + As of PHP 8.0.0, the variable name for a caught + Throwable is optional. + If not specified, the &catch; block will still execute but will not + have access to the thrown object. + + + Omitting the caught variable + Only permitted in PHP 8.0.0 and later. + + +]]> + + + + diff --git a/language/error-handling.xml b/language/error-handling.xml new file mode 100644 index 000000000000..a5a69a8e157f --- /dev/null +++ b/language/error-handling.xml @@ -0,0 +1,323 @@ + + + Error Handling + + 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. + + + PHP has two main mechanisms for reporting errors: + + + + Throwable errors, which are further split into + programming errors via the Error + class hierarchy and recoverable errors via the + Exception class hierarchy. + + + + + Diagnostic errors which are classified into different + severities. + + + + + + + <classname>Throwable</classname> errors + + Most errors in PHP are of this type. + A Throwable error, is an execution event which disrupts + the normal flow of instructions. When a Throwable error + is &throw;n, be that by the engine or manually, it will unwind the call stack + all the way up to the global scope and terminate the program with a fatal error. + All &finally; blocks it encounters along the way will be executed. + + + To throw a Throwable error from within PHP code, one + must use the &throw; keyword followed by an instance of the + Error or Exception class or + a subclass of one of them. + Trying to throw an object that is not will result in an + Error being thrown with the following message: + Cannot throw objects that do not implement Throwable. + + + + The Standard PHP Library (SPL) provides + various built-in exceptions. + And it's possible to create custom exceptions by + extending + Exception. + + + + It is possible to handle a Throwable 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. + + + + It is not recommended to catch Error + objects as those signal a programming error. + + + + + Throwable objects cannot be cloned. + Attempting to clone such an + object will result in an Error being thrown with + the following message: + Trying to clone an uncloneable object of class Exception. + + + + + <literal>Global exception handler</literal> + + If a Throwable object is allowed to bubble up to the + global scope, it may be caught by a global exception handler if set. + The set_exception_handler 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;. + + + + + Extending Exceptions + + A user-defined exception can be defined by extending the built-in + Exception class. + To see which methods and properties are accessible within a child class + derived from Exception visit its page. + + + If a class extends the built-in Exception class and + re-defines the constructor, + it is highly recommended that it also call parent::__construct() + to ensure all available data has been properly assigned. + The __toString() method can be overridden + to provide a custom output when the object is used as a string. + + + Extending <classname>Exception</classname> + +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"; + echo $e; + $e->customFunction(); +} +]]> + + &example.outputs; + + + + + + + + <classname>Throwable</classname> hierarchy + + + + Throwable + + + Error + + + ArithmeticError + + + DivisionByZeroError + + + + + AssertionError + + + CompileError + + + ParseError + + + + + TypeError + + + ArgumentCountError + + + + + ValueError + + + UnhandledMatchError + + + + + Exception + + + ... + + + + + + + + + + + Diagnostic errors + + 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, + E_NOTICE and E_DEPRECATED + diagnostics were not reported by default.) + + + In contrast to Throwable errors, diagnostic errors do + not disrupt the normal flow of execution. + + + Which diagnostics are reported and which are ignored is controlled by the + error_reporting + &php.ini; directive, or at runtime by calling error_reporting. + It is strongly recommended that the configuration directive be set, + as some errors can occur before execution of your script begins. + + + + In a development environment, + error_reporting + should always be set to E_ALL to be aware of and fix + issues raised by PHP. + However, in production the level of verbosity could be reduced to + E_ALL & ~E_NOTICE & ~E_DEPRECATED, but in many cases + E_ALL is still appropriate, as it may provide early + warning of potential issues. + + + + + What happens to the diagnostics depends on two further &php.ini; directives. + display_errors + 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. + + + + In addition to displaying errors, PHP can log diagnostics when the + log_errors + directive is enabled. This will log any diagnostic to the file or syslog + defined by + error_log. + 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. + + + Individual diagnostics can be suppressed using the + @ operator. + + + + + Prior to PHP 8.0.0 it was possible to suppress critical diagnostics that + would terminate the execution of the PHP script. + + + + + + Diagnostics can be added, removed, have their severity altered or be + elevated to a Throwable error in between PHP versions. + + + + + User-defined diagnostic handler + + + If PHP's default diagnostic handling is inadequate, + it is possible to override the default diagnostic handler with a custom one + which is set by using set_error_handler. + Only non-fatal diagnostic can be handled this way, but they can then 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. + + + + Another typical usage is to elevate diagnostic errors to exceptions with + ErrorException. + + + Elevating diagnostic errors to exceptions + + +]]> + + + + It is important to verify that the severity is included in the current + list of reportable diagnostics, otherwise the + @ operator + will be broken, as an exception will be thrown for a suppressed diagnostic. + + + + + + + diff --git a/language/oop5/basic.xml b/language/oop5/basic.xml index 74d188eaa695..c4c5ebf9d2d9 100644 --- a/language/oop5/basic.xml +++ b/language/oop5/basic.xml @@ -201,7 +201,7 @@ readonly class Foo To create an instance of a class, the new keyword must be used. An object will always be created unless the object has a constructor defined that throws an - exception on error. Classes + Exception on error. Classes should be defined before instantiation (and in some cases this is a requirement). diff --git a/language/oop5/changelog.xml b/language/oop5/changelog.xml index a57f29ba56ce..9b865e948276 100644 --- a/language/oop5/changelog.xml +++ b/language/oop5/changelog.xml @@ -197,7 +197,7 @@ 5.5.0 - Added: finally to handle exceptions. + Added: finally to handle exceptions. @@ -255,9 +255,9 @@ Changed: Prior to 5.3.0, exceptions thrown in the __autoload function could not be - caught in the catch block, and + caught in the catch block, and would result in a fatal error. Exceptions now thrown in the __autoload function - can be caught in the catch block, with + can be caught in the catch block, with one provison. 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/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; + language/error-handling.xml. --> &language.predefined.error; &language.predefined.argumentcounterror; &language.predefined.arithmeticerror; diff --git a/reference/dom/domexception.xml b/reference/dom/domexception.xml index bee004bb55ca..f37578b88ad5 100644 --- a/reference/dom/domexception.xml +++ b/reference/dom/domexception.xml @@ -26,7 +26,7 @@ FIXME: Remove me once you perform substitutions Dom namespace. - See also . + See also . diff --git a/reference/pdo/error-handling.xml b/reference/pdo/error-handling.xml index 83bb4c22d0fd..c94dfcd69acd 100644 --- a/reference/pdo/error-handling.xml +++ b/reference/pdo/error-handling.xml @@ -58,8 +58,8 @@ checking the return value of each database call. - See Exceptions for more - information about Exceptions in PHP. + See for more + information about handling Exceptions in PHP. diff --git a/reference/pdo/pdoexception.xml b/reference/pdo/pdoexception.xml index b7d4ab81bdab..efcdb0f3da9a 100644 --- a/reference/pdo/pdoexception.xml +++ b/reference/pdo/pdoexception.xml @@ -12,8 +12,9 @@ Represents an error raised by PDO. You should not throw a PDOException from your own code. - See Exceptions for more - information about Exceptions in PHP. + + + See also . diff --git a/reference/snmp/snmpexception.xml b/reference/snmp/snmpexception.xml index 156d570bc847..596bdb742073 100644 --- a/reference/snmp/snmpexception.xml +++ b/reference/snmp/snmpexception.xml @@ -12,8 +12,9 @@ Represents an error raised by SNMP. You should not throw a SNMPException from your own code. - See Exceptions for more - information about Exceptions in PHP. + + + See also . diff --git a/reference/stomp/stompexception.xml b/reference/stomp/stompexception.xml index c4f911ac5295..61f3621e3130 100644 --- a/reference/stomp/stompexception.xml +++ b/reference/stomp/stompexception.xml @@ -12,7 +12,10 @@
&reftitle.intro; -Represents an error raised by the stomp extension. See Exceptions for more information about Exceptions in PHP. + Represents an error raised by the stomp extension. + + + See also .