rfc:enhanced_error_handling

Differences

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

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
rfc:enhanced_error_handling [2009/12/29 09:54] kampfcasparrfc:enhanced_error_handling [2017/09/22 13:28] (current) – external edit 127.0.0.1
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 behaviour has to be in the hands of the user (php coder). He has to handle the situation and live with the consequences of failed calls. 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 for a whole script in production systems (redirecting to a "sorry, something went wrong" page).+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 86: Line 107:
 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.
  
-===== Implementation =====+===== C API ===== 
 + 
 +The following does not represent compilable code.
  
 ==== Error Container ==== ==== Error Container ====
  
-Each level mentioned above would need storage for error parameters as well as error results:+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> <code c>
-  struct _error_container +  struct error_container 
-    // identification +    char *name;                         // identification, e.g. extension name 
-    char *name;+    error_container *parent           // hierarchy: inherit parent's configuration 
 +    error_container *delegate;          // hierarchy: "last" error is in a child from this one
  
-    // used to propagate errors up/down +    error_action     action;            // error behaviour for this container 
-    error_container *parent+    long             level            // default E_* 
-    error_container *delegate;+    zend_class_entry *exception       // default exception class
  
-    // parameters as set by ini or api +    error_incident incident;            // last error'information on this container's level
-    enum error_behaviour behaviour; +
-    zend_bool            force_behaviour; +
-    long                 level; +
-    char *               exception; +
-    zend_bool            force_parameters; +
- +
-    // last error'data +
-    char *container+
-    long  code; +
-    char *msg;+
   }   }
 </code> </code>
- 
-  * **name**\\ There would be a global container (probably NULL), per extension (extension name) and per object ("object container") 
-  * **parent**\\ Used to create the hierarchy of containers, e.g. to force a behaviour to lower containers 
-  * **delegate**\\ Rather than copying error data two or even three times, set a pointer to the real data (container's destructors will have to correct pointers) 
-  * **behaviour**\\ Some enum for the behaviours mentioned above 
-  * **force-* **\\ Do force either behaviour or parameters for this container and children 
-  * **level**\\ Either default or forced error level (E_*) for zend_error() 
-  * **exception**\\ Either default or forced exception name (name instead of ce ptr allows to autoload) 
-  * **container**\\ In which container the error did occur (for user presentation) 
-  * **code** / **msg**\\ The usual error parameters 
  
 ==== Error Function ==== ==== Error Function ====
  
 <code c> <code c>
-  void error_throw( error_container *container, long level, char *exception, long code TSRMLS_DC, char *format, ...);+  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> </code>
  
-Each use of the error function should nevertheless be followed by a defined return value.+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.
  
-==== User API ====+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.
  
-<code> +==== Utility functions ===
-  int    error_get_code( [string|object] ); +
-  string error_get_message( [string|object] ); +
-  string error_get_origin( [string|object] );+
  
-  void   error_set_behaviour( [string|object]$behaviour ); +Apart from the error issuing functionseveral utility functions are needed, e.g.: 
-  void   error_set_parameters( [string|object], $errorlevel [, $exception] ); +  * Creation/Destruction of error containers 
-  void   error_reset_behaviour( [string|object] ); +  * Setting/Resetting error behaviour of containers 
-  void   error_reset_parameters( [string|object] ); +  * Reading error incidents 
-</code>+  * Clearing error incidents
  
-A container should be identifiable as NULL (global), a string (e.g. extension containers) or by giving an object that supports this scheme. As written above, any error should "trickle up" the chain, such that an error_get_code() gets the (globally) last error's code, even if it happend in a child container.+The corresponding API depends too much on implementation detais to discuss those here.
  
-The same functions could be used as methods in objects supporting this scheme.+===== PHP API =====
  
-==== Integration ====+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.
  
-Short of extending core structures of the Zend Engine and for better backwards compatibility, the error containers would have to be held in a hash. Extensions and objects would be able to "registertheir container - as well as unregister them upon destruction. Extension names and object handles could be used as keys. As errors should be a relatively rare occurence, not much overhead is to be expected.+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 157: 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...
  
 ===== Course of Action and Patch ===== ===== Course of Action and Patch =====
  
-  - An intl extension-level implementation is being created by kampfcaspar at https://saintcyr.oeri.ch/trac/php-intl/+  - Development: https://saintcyr.oeri.ch/trac/php-error/
   - Given enough feedback and operating experience, the enhanced error handling could be bundled in an "error extension"   - Given enough feedback and operating experience, the enhanced error handling could be bundled in an "error extension"
   - Other extensions could use the "error extension"   - Other extensions could use the "error extension"
Line 174: Line 205:
 | 2009-12-27  | kampfcaspar | Created Initial Version | | 2009-12-27  | kampfcaspar | Created Initial Version |
 | 2009-12-28  | kampfcaspar | Added draft API         | | 2009-12-28  | kampfcaspar | Added draft API         |
 +| 2010-01-07  | kampfcaspar | Overhaul                | 
 +| 2010-01-10  | kampfcaspar | +Differences Observed   |
rfc/enhanced_error_handling.1262080456.txt.gz · Last modified: 2017/09/22 13:28 (external edit)