rfc:enhanced_error_handling

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
rfc:enhanced_error_handling [2009/12/27 19:12]
kampfcaspar created
rfc:enhanced_error_handling [2017/09/22 13:28] (current)
Line 1: Line 1:
 ====== Request for Comments: Enhanced Error Handling ====== ====== Request for Comments: Enhanced Error Handling ======
-  * Version: 0.1 +  * Version: 0.5 
-  * Date:    ​2009-12-27+  * Date:    ​2010-01-10
   * Author: ​ Hans-Peter Oeri <​hp@oeri.ch>​   * Author: ​ Hans-Peter Oeri <​hp@oeri.ch>​
-  * Status:  ​Drafting+  * Status:  ​Draft (Inactive)
   * First Published at: http://​wiki.php.net/​rfc/​enhanced_error_handling   * First Published at: http://​wiki.php.net/​rfc/​enhanced_error_handling
  
 ===== Introduction ===== ===== Introduction =====
  
-php_error(), ​zend_throw_extension(), the @-operator... PHP and/or the Zend Engine respectively offer a variety of error issuance and handling mechanisms. There is, however, no encompassing concepts: Core functions only issue php_errors (suppressable),​ intl 1.0.3 by default suppresses all errors but can activate php_errors, pdo however has a proprietary ​flag to define error behaviour that allows exceptions - but limits php_error to E_WARNING.+php_error(), ​zend_throw_exception(), the @-operator... PHP and/or the Zend Engine respectively offer a variety of error issuance and handling mechanisms. There is, however, no encompassing concepts: Core functions only issue php_errors (suppressable),​ intl 1.0.3 by default suppresses all errors but can activate php_errors, pdo however has a flag to define error behaviour that allows exceptions - but limits php_error to E_WARNING. Furthermore,​ each extension has a different way of changing its error behaviour etc. etc.
  
-state that error handling ​has to be in the hands of the user (php coder). ​Some may prefer ​php_error()s,​ others prefer exceptions; some are ok with E_WARNINGs that indicate severe ​situations, others prefer E_ERROR for those cases; and some might want to either suppress all messages or default to a big exception block per script in production systems.+think that error behaviour ​has to be in the hands of the user (php coder). ​Different users have different preferences - and prefer ​different behaviour in different ​situations.
  
-===== Scope =====+==== Scope ====
  
 Error conditions are encountered in a variety of places and cases. This RFC only covers error conditions in a running script, e.g. a file was not found. Error conditions are encountered in a variety of places and cases. This RFC only covers error conditions in a running script, e.g. a file was not found.
  
 All other situations - like compilation problems, core errors in engine startup/​shutdown - are out of scope. All other situations - like compilation problems, core errors in engine startup/​shutdown - are out of scope.
 +
 +==== Differences Observed ====
 +
 +  * Almost all error behaviours include a human readable //error message// and a machine readable //error code//; the '​original'​ zend_error however, does not define error codes, but far less granular //error types// (which are nevertheless named errno in parts of the docs, e.g. set_error_handler).
 +  * Error codes - if used - do not follow any //common semantic rules// and are therefore not interpretable without knowing their source; even more, they might be defined externally (SQLSTATE or linked library).
 +  * While traditionally error numbers have mostly been numeric, also //​alphanumeric//​ variants exist (SQLSTATE).
 +  * Error codes and - to a lesser extent - error messages are traditionally held in a special variable or place for later inspection. Information held there may be reset //upon request/new error// (errno in C, error_get_last in PHP) or with any subsequent //​successful action/​call//​ (PDO, intl).
 +  * There may be just a //single holding space// for later inspection of error information (error_get_last),​ a a //​compartementalized//​ holding space for independent error information (PDO vs. PDOStatement) or even a //​hierarchical//​ one, which combines the earlier two (intl).
 +  * Functions not bailing out on error situations should return a //defined error value//. There is, however, a  variety of defined error values - also dependent on the required valid return value range, which might include values that other functions use as error indicating value.
 +  * Definition of error actions - as described in the introduction - is handled by //php.ini// or //object calls// or //not available// at all. None of it offers all options.
 +
 +
 +===== Goals =====
 +
 +The goal would be to create a framework in which
 +  * the //PHP user// decides, what kind of error reaction he wishes; that includes
 +  * having a single //error call// that abstracts away from zend_errors/​exceptions and
 +  * a minimal //​inheritance of error behaviours//,​ such that different extensions and/or resource objects might be configured to react differently.
 +  * offers a //C-level API// for compiled extensions as well as a //PHP-level API// for frameworks in that language.
 +  * can be used in //OOP// as well as //non-OOP// situations.
 +
 +
 +Such goals can only be achieved under the side condition of //complete backwards compatibility//​. Default behaviour of
 +existing php and extensions must not be changed - all existing error behaviour must be mappable.
  
 ===== Definitions ===== ===== Definitions =====
  
-==== Error Behaviours ​====+==== Error Actions ​====
  
 If an error condition is met, different types of reactions are possible: If an error condition is met, different types of reactions are possible:
 ^ Name               ^ Description ​                             ^ ^ Name               ^ Description ​                             ^
 | Suppress ​          | Note down error and return an //error value//, e.g. false/NULL | | Suppress ​          | Note down error and return an //error value//, e.g. false/NULL |
 +| Monitor ​           | same as Suppress, but let a php monitor know - independent of error handling taken by user code|
 | Error              | same as Suppress, but issue a php_error as well | | Error              | same as Suppress, but issue a php_error as well |
 | Throw              | same as Suppress, but throw an exception as well | | Throw              | same as Suppress, but throw an exception as well |
  
-The error behaviour ​should be configurable by the user; preferably system-wide and +The error action ​should be configurable by the user. An extension should ​usually ​not differ from the user's wishes.
-overridable. An extension should not, however, decide to differ from the user's wishes.+
  
-In any case, there should be a method to get at the noted-down error information,​ e.g. +Noted-down error information,​ e.g. error code and message ​etc., would be available by a standardized API. 
-error code and message.+ 
 +==== Error Levels ==== 
 + 
 +Existing extensions use their error mechanisms not only to issue grave errors, but also to 
 +transport mere "​warnings"​ to the user - much like a message transport. As this is pre-existing,​ 
 +both an //error// and a //warning// call should be supplied. The latter - ignoring all configuration - 
 +choosing Suppress or Monitor as appropraiate action.
  
 ==== Error Parameters ==== ==== Error Parameters ====
  
-php_error ​needs an E_* value to distinguish warnings and errors and the Throw behaviour+Different behaviours, ask for different additional parameters:  
 +zend_error ​needs an E_* value to distinguish warnings and errors and throwing an exception
 needs an exception class. needs an exception class.
  
-Defaults ​for those parameters should be configurable like the error behaviourThe extension +Default values ​for those parameters should be configurable like the error actionHowevermore specific 
-should however be ablewhile issuing an error, to set appropriate parameters if necessary. +values ​- like an BadFunctionCallException while testing parameters ​have to be definable with the 
- +error call itself.
-For extreme cases - like "one big exception block per script" ​- the default parameters +
-should be enforcable by the user's wishes.+
  
 ==== Error Container Hierarchy ==== ==== Error Container Hierarchy ====
  
-PHP lives of its extensibility. ​An extension can offer a whole bunch of different ​classes +PHP lives of its extensibility. ​Different extensions currently show different 
-that are related; take ''​intl''​ as an example. It could be interesting for the user +default error behaviours. It goes without saying, that error behaviour must 
-to differentiate his error reactions ​by object and/or extension.  +keep being configurable //by extension//.
-He could wish to let the whole of ''​intl''​ throw a PersonalIntlExceptionClass upon errors or +
-decide to switch to exceptions for a long block of translation calls (not testing each +
-and every result on its own) while he usually prefers E_ERRORS being issued.+
  
-The proposal therefore stands for three-level hierarchy:+As some extensions currently do, I propose to add layer of error 
 +configurability on //​object ​level// (see e.g. PDO -> by PDO connection). They should 
 +default to the extension'​s behaviour, but be configurable differently.
  
-^ Level           ^ Description ^ +Without any hassle, //​inheritance//​ could be implementedThe error configuration on 
-| Global ​         | Define behaviour and default parameters | +PDO connection could be inherited its PDOStatements.
-|                 | Could be used to force behaviour as well as parameterseg. in production | +
-| Field/Extension | Inherits from Global level | +
-|                 | Overrides behaviour and parameters for a "​field",​ e.g. all i18n in intl.so| +
-| Object ​         | Inherits from Field level | +
-|                 | Overrides behaviour and parameters for single object | +
- +
-If any level enforces behaviour and/or parameters, the lower levels will not deviate.+
  
 ===== Special Cases ===== ===== Special Cases =====
Line 70: Line 91:
 ==== Enforced Exception class ==== ==== Enforced Exception class ====
  
-Each level could enforce the use of a specific exception class, e.g. PersonalIntlExceptionClass() for all of intl.so. While forcing such a common class does ease catching, some information a more specific class could provide is lost.+A lower hierarchy ​level could enforce the use of a specific exception class, e.g. PersonalIntlExceptionClass() for all of intl.so. While forcing such a common class does ease catching, some information a more specific class could provide is lost.
  
-As of PHP 5.3, the concept of exception chaining has been introduced, whereas a "​previous" ​extension ​can be attached. In order to keep the previously lost information,​ the concrete exception class given upon issuing an error should be chained to the enforced class.+As of PHP 5.3, the concept of exception chaining has been introduced, whereas a "​previous" ​exception ​can be attached. In order to keep the previously lost information,​ the concrete exception class given upon issuing an error should be chained to the enforced class.
  
 ==== Notices ==== ==== Notices ====
Line 85: Line 106:
  
 If possible, the operator should be limited to errors in the execution of scripts but "​silence"​ thrown exceptions as well (like a "per object"​ Suppress above). It's functionality should be prohibited, if a certain behaviour is enforced. If possible, the operator should be limited to errors in the execution of scripts but "​silence"​ thrown exceptions as well (like a "per object"​ Suppress above). It's functionality should be prohibited, if a certain behaviour is enforced.
 +
 +===== C API =====
 +
 +The following does not represent compilable code.
 +
 +==== Error Container ====
 +
 +The levels mentioned above would need a common container structure to hold error
 +configuration as well as "last error" information. The same construct can be hold
 +by extensions as well as objects.
 +
 +<code c>
 +  struct error_container {
 +    char *name; ​                        // identification,​ e.g. extension name
 +    error_container *parent; ​           // hierarchy: inherit parent'​s configuration
 +    error_container *delegate; ​         // hierarchy: "​last"​ error is in a child from this one
 +
 +    error_action ​    ​action; ​           // error behaviour for this container
 +    long             ​level; ​            // default E_*
 +    zend_class_entry *exception; ​       // default exception class
 +
 +    error_incident incident; ​           // last error'​s information on this container'​s level
 +  }
 +</​code>​
 +
 +==== Error Function ====
 +
 +<code c>
 +  error_behaviour error_yell( error_container *container, long level, char *exception, long code, char *msg );
 +  error_behaviour error_yellf( error_container *container, long level, char *exception, long code, char *format, ... );
 +</​code>​
 +
 +Instead of writing explicit calls to zend_error or zend_exception_throw,​ this call abstracts away the
 +error behaviour. It does, however return the //actual// action initiated.
 +
 +As errors might be suppressed, after the use of error_yell a defined return value should be returned to PHP.
 +One //cannot// be sure that the engine will branch away into an error or exception handler.
 +
 +==== Utility functions ===
 +
 +Apart from the error issuing function, several utility functions are needed, e.g.:
 +  * Creation/​Destruction of error containers
 +  * Setting/​Resetting error behaviour of containers
 +  * Reading error incidents
 +  * Clearing error incidents
 +
 +The corresponding API depends too much on implementation detais to discuss those here.
 +
 +===== PHP API =====
 +
 +Apart from extensions in C, php code itself could use such unified error configuration as well.
 +Above mentioned error_yell function as well as utility functions to configure error actions and
 +read error information should be available.
 +
 +A standard ErrorClass - implementing an object
 +level error container plus standardized methods to access it - should be available:
 +
 +<code php>
 +  class ErrorClass {
 +    function __construct( $parent_container )
 +    function setErrorAction(...);​
 +    function resetErrorAction();​
 +    function yellError(...);​
 +    function getLastError();​
 +  }
 +</​code>​
 +
 +Of course, the internal ErrorClass could be used as base class for
 +extension classes as well.
 +
 +Error containers would be identified by:
 +  * NULL: global/​highest hierarchy
 +  * string: extension-level container (e.g. in a hash)
 +  * ErrorClass: object-level container
 +
 +In order to allow PHP frameworks to depend on an "​extension level" container,
 +such a string-identified container should be creatable on user level.
  
 ===== Backwards Compatibility ===== ===== Backwards Compatibility =====
Line 90: Line 188:
 ==== Extensions ==== ==== Extensions ====
  
-Extensions can keep backwards compatibility,​ if their current default behaviour is mapped to the above-mentioned ​Field level. Even special cases should be representable with the mentioned ​behaviours, parameters and enforcement.+Extensions can keep backwards compatibility,​ if their current default behaviour is mapped to the above-mentioned ​extension ​level. Even special cases should be representable with the mentioned ​actions, parameters and enforcement.
  
 ==== Core ==== ==== Core ====
  
-I would personally not touch the core, but it's error behaviour ​should be representable as well.+The core should ​probably only be touched if this proposal (or something analogous) is included in it...
  
-===== Proposal ​and Patch =====+===== Course of Action ​and Patch =====
  
-An intl extension-level implementation is being created by kampfcaspar at +  ​Development: ​https://​saintcyr.oeri.ch/​trac/​php-error/ 
-https://​saintcyr.oeri.ch/​trac/​php-intl/+  - Given enough feedback and operating experience, the enhanced error handling could be bundled in an "error extension"​ 
 +  - Other extensions could use the "error extension"​
  
 ===== Changelog ===== ===== Changelog =====
Line 105: Line 204:
 ^ Date        ^ Author ​     ^ Message ​                ^ ^ Date        ^ Author ​     ^ Message ​                ^
 | 2009-12-27 ​ | kampfcaspar | Created Initial Version | | 2009-12-27 ​ | kampfcaspar | Created Initial Version |
 +| 2009-12-28 ​ | kampfcaspar | Added draft API         | 
 +| 2010-01-07 ​ | kampfcaspar | Overhaul ​               | 
 +| 2010-01-10 ​ | kampfcaspar | +Differences Observed ​  |
rfc/enhanced_error_handling.1261941129.txt.gz · Last modified: 2017/09/22 13:28 (external edit)