mirror of
https://github.com/sigmasternchen/php-doc-en
synced 2025-03-15 16:38:54 +00:00

We were getting an Error trying to pass null to construct an exception, and found that "" works but null doesn't. Also correcting the inheritance keyword since Throwable is an interface. This brings these docs more into line with the PHPStorm stubs. Closes GH-668.
557 lines
15 KiB
XML
557 lines
15 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<!-- $Revision$ -->
|
|
<chapter xml:id="language.exceptions" xmlns="http://docbook.org/ns/docbook">
|
|
<title>Exceptions</title>
|
|
|
|
<sect1 xml:id="language.exceptions.extending">
|
|
<title>Extending Exceptions</title>
|
|
<para>
|
|
A User defined Exception class can be defined by extending the built-in
|
|
Exception class. The members and properties below, show what is accessible
|
|
within the child class that derives from the built-in Exception class.
|
|
</para>
|
|
<example>
|
|
<title>The Built in Exception class</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class Exception implements Throwable
|
|
{
|
|
protected $message = 'Unknown exception'; // exception message
|
|
private $string; // __toString cache
|
|
protected $code = 0; // user defined exception code
|
|
protected $file; // source filename of exception
|
|
protected $line; // source line of exception
|
|
private $trace; // backtrace
|
|
private $previous; // previous exception if nested exception
|
|
|
|
public function __construct($message = '', $code = 0, Throwable $previous = null);
|
|
|
|
final private function __clone(); // Inhibits cloning of exceptions.
|
|
|
|
final public function getMessage(); // message of exception
|
|
final public function getCode(); // code of exception
|
|
final public function getFile(); // source filename
|
|
final public function getLine(); // source line
|
|
final public function getTrace(); // an array of the backtrace()
|
|
final public function getPrevious(); // previous exception
|
|
final public function getTraceAsString(); // formatted string of trace
|
|
|
|
// Overrideable
|
|
public function __toString(); // formatted string for display
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
<para>
|
|
If a class extends the built-in Exception class and re-defines the <link
|
|
linkend="language.oop5.decon">constructor</link>, it is highly recommended
|
|
that it also call <link
|
|
linkend="language.oop5.paamayim-nekudotayim">parent::__construct()</link>
|
|
to ensure all available data has been properly assigned. The <link
|
|
linkend="language.oop5.magic">__toString()</link> method can be overridden
|
|
to provide a custom output when the object is presented as a string.
|
|
</para>
|
|
<note>
|
|
<para>
|
|
Exceptions cannot be cloned. Attempting to <link
|
|
linkend="language.oop5.cloning">clone</link> an Exception will result in a
|
|
fatal <constant>E_ERROR</constant> error.
|
|
</para>
|
|
</note>
|
|
<example>
|
|
<title>Extending the Exception class</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;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Example 1
|
|
try {
|
|
$o = new TestException(TestException::THROW_CUSTOM);
|
|
} catch (MyException $e) { // Will be caught
|
|
echo "Caught my exception\n", $e;
|
|
$e->customFunction();
|
|
} catch (Exception $e) { // Skipped
|
|
echo "Caught Default Exception\n", $e;
|
|
}
|
|
|
|
// Continue execution
|
|
var_dump($o); // Null
|
|
echo "\n\n";
|
|
|
|
|
|
// Example 2
|
|
try {
|
|
$o = new TestException(TestException::THROW_DEFAULT);
|
|
} catch (MyException $e) { // Doesn't match this type
|
|
echo "Caught my exception\n", $e;
|
|
$e->customFunction();
|
|
} catch (Exception $e) { // Will be caught
|
|
echo "Caught Default Exception\n", $e;
|
|
}
|
|
|
|
// Continue execution
|
|
var_dump($o); // Null
|
|
echo "\n\n";
|
|
|
|
|
|
// Example 3
|
|
try {
|
|
$o = new TestException(TestException::THROW_CUSTOM);
|
|
} catch (Exception $e) { // Will be caught
|
|
echo "Default Exception caught\n", $e;
|
|
}
|
|
|
|
// Continue execution
|
|
var_dump($o); // Null
|
|
echo "\n\n";
|
|
|
|
|
|
// Example 4
|
|
try {
|
|
$o = new TestException();
|
|
} catch (Exception $e) { // Skipped, no exception
|
|
echo "Default Exception caught\n", $e;
|
|
}
|
|
|
|
// Continue execution
|
|
var_dump($o); // TestException
|
|
echo "\n\n";
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</sect1>
|
|
|
|
<simplesect xml:id="language.exceptions.introduction">
|
|
<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 instance of the
|
|
<classname>Exception</classname> class or a subclass of
|
|
<classname>Exception</classname>. Trying to throw an object that is not
|
|
will result in a PHP Fatal Error.
|
|
</para>
|
|
<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>
|
|
|
|
</simplesect>
|
|
|
|
<simplesect 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>
|
|
</simplesect>
|
|
|
|
<simplesect 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>
|
|
</simplesect>
|
|
|
|
<simplesect xml:id="language.exceptions.exception-handler">
|
|
<title><literal>Global exception handler</literal></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>
|
|
</simplesect>
|
|
|
|
<simplesect xml:id="language.exceptions.notes">
|
|
&reftitle.notes;
|
|
|
|
<note>
|
|
<para>
|
|
Internal PHP functions mainly use
|
|
<link linkend="ini.error-reporting">Error reporting</link>, only modern
|
|
<link linkend="language.oop5">Object oriented</link>
|
|
extensions use exceptions. However, errors can be 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">
|
|
<![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>
|
|
</simplesect>
|
|
|
|
<simplesect xml:id="language.exceptions.examples">
|
|
&reftitle.examples;
|
|
|
|
<example>
|
|
<title>Throwing an Exception</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
function inverse($x) {
|
|
if (!$x) {
|
|
throw new Exception('Division by zero.');
|
|
}
|
|
return 1/$x;
|
|
}
|
|
|
|
try {
|
|
echo inverse(5) . "\n";
|
|
echo inverse(0) . "\n";
|
|
} catch (Exception $e) {
|
|
echo 'Caught exception: ', $e->getMessage(), "\n";
|
|
}
|
|
|
|
// Continue execution
|
|
echo "Hello World\n";
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
&example.outputs;
|
|
<screen>
|
|
<![CDATA[
|
|
0.2
|
|
Caught exception: Division by zero.
|
|
Hello World
|
|
]]>
|
|
</screen>
|
|
</example>
|
|
<example>
|
|
<title>Exception handling with a &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>
|
|
<example>
|
|
<title>Throw as an expression</title>
|
|
<para>Only permitted in PHP 8.0.0 and later.</para>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
|
|
class SpecificException extends Exception {}
|
|
|
|
function test() {
|
|
do_something_risky() or throw new Exception('It did not work');
|
|
}
|
|
|
|
try {
|
|
test();
|
|
} catch (Exception $e) {
|
|
print $e->getMessage();
|
|
}
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</simplesect>
|
|
|
|
</chapter>
|
|
|
|
<!-- Keep this comment at the end of the file
|
|
Local variables:
|
|
mode: sgml
|
|
sgml-omittag:t
|
|
sgml-shorttag:t
|
|
sgml-minimize-attributes:nil
|
|
sgml-always-quote-attributes:t
|
|
sgml-indent-step:1
|
|
sgml-indent-data:t
|
|
indent-tabs-mode:nil
|
|
sgml-parent-document:nil
|
|
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
|
|
sgml-exposed-tags:nil
|
|
sgml-local-catalogs:nil
|
|
sgml-local-ecat-files:nil
|
|
End:
|
|
vim600: syn=xml fen fdm=syntax fdl=2 si
|
|
vim: et tw=78 syn=sgml
|
|
vi: ts=1 sw=1
|
|
-->
|