This is an old revision of the document!
PHP RFC: Throwable Interface
- Date: 2015-05-22
- Author: Aaron Piotrowski aaron@icicle.io
- Status: Draft
- First Published at: http://wiki.php.net/rfc/throwable-interface
Introduction
PHP 7 has introduced exceptions as a replacement for fatal or recoverable fatal errors. These exceptions do not extend Exception
, but instead extend a new class BaseException
and are named EngineException
, TypeException
, and ParseException
. These
The current exception hierarchy implemented for PHP 7 has a naming scheme that is unintuitive and will lead to confusion, especially for newer users.
Example:
function add(int $left, int $right) { return $left + $right; }; try { echo add('left', 'right'); } catch (Exception $e) { // Handle or log exception. }
The code above will not catch the TypeException
thrown due to the mis-matched type-hint, resulting in the following message to the user:
Fatal error: Uncaught TypeException: Argument 1 passed to add() must be of the type integer, string given
The reason that an object named TypeException
would not be caught by catch (Exception $e)
is not obvious.
Proposal
This RFC proposes a change to the exception hierarchy for PHP 7. This proposal is based on the Throwable pull request created by Sebastian Bergmann and has been fully implemented in the Throwable Interface pull request.
interface Throwable
Exception implements Throwable
Error implements Throwable
(ReplacesEngineException
)TypeError extends Error
ParseError extends Error
BaseException
will be removed. In order for an object to be thrown, it must implement the Throwable
interface.
The Throwable
interface specifies the following methods:
getMessage()
getCode()
getFile()
getLine()
getTrace()
getTraceAsString()
__toString()
While both Exception
and Error
are implemented using the same code in the interpreter, the Throwable
interface does not preclude future classes from implementing the interface differently.
catch (Error $e)
and catch (Throwable $e)
may respectively be used to catch Error
objects or any Throwable
(current or future) object. Users should be discouraged from catching Error
objects object except for logging or cleanup purposes as Error
objects represent coding problems that should be fixed rather than runtime conditions that may be handled.
Error Name Choice
The name Error
was chosen to correspond with PHP's other errors. Non-fatal errors will issue warnings and notices, while fatal errors are thrown. While this may also cause some confusion for users, other name choices for the class such as Failure
seem equally problematic. It is likely that users would search for 'Uncaught Error' when searching for the reason behind the problem and would minimize overlap with with warning and notice messages. Users may even wish to use set_error_handler()
to throw objects extending Error
in their code for any type of error.
AssertionException
If this RFC is accepted, AssertionException
should instead extend Error
and be renamed to AssertionError
as suggested in the Expectations RFC.
Proposed PHP Version
PHP 7
Backwards Compatibility
Throwable
, Error
, TypeError
, and ParseError
will no longer be available in the global namespace.
Patch
A patch for this RFC is available at https://github.com/php/php-src/pull/1284.
The patch prevents user classes from implementing Throwable
, preventing users from creating their own throwable branches, ensuring only Exception
and Error
instances can be thrown. Error
instances can be created and extended by users, allowing users to create throwable Error
objects to create their own fatal errors.
References
- Throwable Interface Pull Request by Aaron Piotrowski
- Throwable Pull Request by Sebastian Bergmann