This is an old revision of the document!
PHP RFC: Throwable Interface
- Version: 0.1.2
- 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 classes have 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 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 ThrowableException implements ThrowableError implements Throwable(ReplacesEngineException)TypeError extends ErrorParseError extends Error
BaseException will be removed.
Only objects that implement the Throwable interface can be thrown. The proposed patch does not allow userland classes to implement the Throwable interface. Instead all classes declared in userland must extend one of the existing exception classes.
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 or from the implementation of Exception and Error to be different in the future.
catch (Error $e) and catch (Throwable $e) may be used to catch respectively Error objects or any Throwable (current or future) object. Users should be discouraged from catching Error objects 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 such as Failure do not seem appropriate. It is likely that users would use the term 'Uncaught Error' when searching, minimizing overlap with with warning and notice messages.
Users may 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