rfc:engine_exceptions
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionLast revisionBoth sides next revision | ||
rfc:engine_exceptions [2013/10/23 18:29] – correct factual error nikic | rfc:engine_exceptions [2013/12/14 16:01] – RFC declined for 5.6 nikic | ||
---|---|---|---|
Line 2: | Line 2: | ||
* Date: 2013-10-23 | * Date: 2013-10-23 | ||
* Author: Nikita Popov < | * Author: Nikita Popov < | ||
- | * Status: | + | * Status: |
* Proposed for: PHP 5.6 | * Proposed for: PHP 5.6 | ||
* Patch: https:// | * Patch: https:// | ||
+ | * ML discussion: http:// | ||
===== Introduction ===== | ===== Introduction ===== | ||
Line 10: | Line 11: | ||
This RFC proposes to allow the use of exceptions in the engine and to allow the replacement of existing fatal or recoverable fatal errors with exceptions. | This RFC proposes to allow the use of exceptions in the engine and to allow the replacement of existing fatal or recoverable fatal errors with exceptions. | ||
- | As an example of this change, consider | + | As an example of this change, consider the following code-snippet: |
<code php> | <code php> | ||
Line 91: | Line 92: | ||
=== Cannot be gracefully handled === | === Cannot be gracefully handled === | ||
- | The most obvious issue with fatal errors is that they immidiately | + | The most obvious issue with fatal errors is that they immediately |
As an example consider a server or daemon written in PHP. If a fatal error occurs during the handling of a request it will abort not only that individual request but kill the entire server/ | As an example consider a server or daemon written in PHP. If a fatal error occurs during the handling of a request it will abort not only that individual request but kill the entire server/ | ||
Line 116: | Line 117: | ||
</ | </ | ||
- | This allows rudimentary handling of fatal errors, but the available information is very limited. In particular the shutdown function is not able to retreive | + | This allows rudimentary handling of fatal errors, but the available information is very limited. In particular the shutdown function is not able to retrieve |
=== Finally blocks will not be invoked === | === Finally blocks will not be invoked === | ||
Line 123: | Line 124: | ||
<code php> | <code php> | ||
- | $lock->aquire(); | + | $lock->acquire(); |
try { | try { | ||
doSomething(); | doSomething(); | ||
Line 131: | Line 132: | ||
</ | </ | ||
- | If '' | + | If '' |
=== Destructors are not called === | === Destructors are not called === | ||
- | When a fatal error occurs destructors are not invoked. This means that anything relying on the RAII (Resource | + | When a fatal error occurs destructors are not invoked. This means that anything relying on the RAII (Resource |
<code php> | <code php> | ||
Line 142: | Line 143: | ||
public function __construct(Lock $lock) { | public function __construct(Lock $lock) { | ||
$this-> | $this-> | ||
- | $this-> | + | $this-> |
} | } | ||
public function __destruct() { | public function __destruct() { | ||
Line 150: | Line 151: | ||
function test($lock) { | function test($lock) { | ||
- | $manager = new LockManager($lock); | + | $manager = new LockManager($lock); |
| | ||
doSomething(); | doSomething(); | ||
Line 174: | Line 175: | ||
=== Hard to catch === | === Hard to catch === | ||
- | While '' | + | While '' |
To catch a recoverable fatal error non-intrusively code along the following lines is necessary: | To catch a recoverable fatal error non-intrusively code along the following lines is necessary: | ||
<code php> | <code php> | ||
- | $oldErrorHandler = set_error_handler(function($errno, | + | set_error_handler(function($errno, |
- | if ($errno === E_RECOVERABLE_ERROR) { | + | if ($errno === E_RECOVERABLE_ERROR) { |
- | throw new ErrorException($errstr, | + | throw new ErrorException($errstr, |
- | } | + | } |
- | return false; | + | return false; |
}); | }); | ||
Line 189: | Line 190: | ||
new Closure; | new Closure; | ||
} catch (Exception $e) { | } catch (Exception $e) { | ||
- | echo " | + | |
} | } | ||
- | set_error_handler($oldErrorHandler); | + | restore_error_handler(); |
</ | </ | ||
==== Solution: Exceptions ==== | ==== Solution: Exceptions ==== | ||
- | Exceptions provide an approach to error handling that does not suffer from the problems of fatal errors | + | Exceptions provide an approach to error handling that does not suffer from the problems of fatal and recoverable |
- | From an implementational point of view they also form a middle | + | From an implementational point of view they also form a middle |
Exceptions have the additional advantage of providing a stack trace. | Exceptions have the additional advantage of providing a stack trace. | ||
Line 222: | Line 223: | ||
Internally the following APIs are added: | Internally the following APIs are added: | ||
- | < | + | < |
// Returns the class_entry for EngineException | // Returns the class_entry for EngineException | ||
ZEND_API zend_class_entry *zend_get_engine_exception(TSRMLS_D); | ZEND_API zend_class_entry *zend_get_engine_exception(TSRMLS_D); | ||
Line 236: | Line 237: | ||
</ | </ | ||
- | Exceptions sometimes need to be thrown before all opcode operands | + | Exceptions sometimes need to be thrown before all opcode operands |
- | < | + | < |
- | // optype-specialized pseudo-macros | + | // Optype-specialized pseudo-macros |
FREE_UNFETCHED_OP1(); | FREE_UNFETCHED_OP1(); | ||
FREE_UNFETCHED_OP2(); | FREE_UNFETCHED_OP2(); | ||
- | // Used for frees in two-op instructions | + | // Used for frees in multi-opline |
static zend_always_inline void _free_unfetched_op(int op_type, znode_op *op, const zend_execute_data *execute_data TSRMLS_DC); | static zend_always_inline void _free_unfetched_op(int op_type, znode_op *op, const zend_execute_data *execute_data TSRMLS_DC); | ||
</ | </ | ||
- | Furthermore the patch accompanying this RFC also contains initial work for moving off '' | + | Furthermore the patch accompanying this RFC contains initial work for replacing existing |
===== Potential issues ===== | ===== Potential issues ===== | ||
Line 255: | Line 256: | ||
Currently it is possible to silently ignore recoverable fatal errors with a custom error handler. By replacing them with exceptions this capability is removed, thus breaking compatibility. | Currently it is possible to silently ignore recoverable fatal errors with a custom error handler. By replacing them with exceptions this capability is removed, thus breaking compatibility. | ||
- | I have never seen this possibility used in practice outside some weird hacks (which use ignored recoverable type constraint errors to implement scalar typehints). In most cases custom error handlers throw an '' | + | I have never seen this possibility used in practice outside some weird hacks (which use ignored recoverable type constraint errors to implement scalar typehints). In most cases custom error handlers throw an '' |
If these concerns are considered significant this RFC might be restricted to '' | If these concerns are considered significant this RFC might be restricted to '' | ||
Line 261: | Line 262: | ||
==== catch-all blocks in existing code ==== | ==== catch-all blocks in existing code ==== | ||
- | As '' | + | As '' |
- | If this is considered to be an issue a solution is to introduce a '' | + | If this is considered to be an issue one possible |
'' | '' | ||
Line 297: | Line 298: | ||
</ | </ | ||
- | Additional improvement (like removing the '' | + | Additional improvement (like removing the '' |
< | < | ||
Line 305: | Line 306: | ||
#1 {main} | #1 {main} | ||
</ | </ | ||
+ | |||
+ | ==== Not all errors converted ==== | ||
+ | |||
+ | The Zend Engine currently (master on 2013-12-10) contains the following number of fatal-y errors: | ||
+ | |||
+ | < | ||
+ | E_ERROR: | ||
+ | E_CORE_ERROR: | ||
+ | E_COMPILE_ERROR: | ||
+ | E_PARSE: | ||
+ | E_RECOVERABLE_ERROR: | ||
+ | </ | ||
+ | |||
+ | The count was obtained using '' | ||
+ | |||
+ | The patch attached to the RFC currently (as of 2013-10-24) removes 70 '' | ||
+ | |||
+ | Some errors are easy to change to exceptions, others are more complicated. Some are impossible, like the memory limit or execution time limit errors. The '' | ||
+ | |||
+ | Converting most existing errors will take some time and in the meantime we'll be in a situation where some part of the errors were converted to exceptions but another part stays fatal. From a user perspective it may not be immediately clear when one is used over the other. | ||
+ | |||
+ | While this may be slightly inconvenient, | ||
+ | |||
+ | ===== Backwards compatibility ===== | ||
+ | |||
+ | The '' | ||
+ | |||
+ | The '' | ||
===== Patch ===== | ===== Patch ===== | ||
Line 310: | Line 339: | ||
A preliminary patch for this RFC is available at https:// | A preliminary patch for this RFC is available at https:// | ||
- | The patch introduces basic infrastructure for this change and removes all '' | + | The patch introduces basic infrastructure for this change and removes all '' |
+ | |||
+ | ===== Vote ===== | ||
+ | |||
+ | This is a yes/no vote with the additional option of implementing the proposal, but without changing '' | ||
+ | |||
+ | As this is a language-related change, the vote requires a two-third majority. The 3-way vote will be interpreted as follows: If 2/3 of the total votes are for " | ||
+ | |||
+ | If you are in favor of this proposal in general, but not for PHP 5.6, use the " | ||
+ | |||
+ | <doodle title=" | ||
+ | * Yes | ||
+ | * Yes, without E_RECOVERABLE_ERROR changes | ||
+ | * No | ||
+ | </ | ||
+ | |||
+ | Vote started on 2013-12-07 and ended on 2013-12-14. |
rfc/engine_exceptions.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1