Xaraya | M. Canini |
Request for Comments: 0018 | Xaraya Development Group |
Category: Informational | May 2002 |
RFC-0018: Exception Handling System
This memo provides information for the Xaraya community. It does not specify an Xaraya standard of any kind. Distribution of this memo is unlimited.
Copyright © The Digital Development Foundation (2002). All Rights Reserved.
This document describes the Exception Handling System technology, an artificial exceptions handling mechanism built on top of the PHP language. This document is constantly subject to revisions. This isn't the final version of the document.
Since the PHP language does not provide native exception handling support (as of writing), we need to create an artificial layer to handle them. The way this document proposes to achieve this goal is closely inspired at the way used by CORBA in the C language mapping. In the case of CORBA the C language mapping imposes that every IDL method accept as last parameter a CORBA_Environment type. We can avoid to use a CORBA_Environment-like parameter for all functions, thanks to, firstly, the non-strongly-typed return values we have in PHP, and secondly, the single threaded policy we adopted in Xaraya.
Here we introduce the following terminology:
Callers can notice of exceptions firstly by checking the called function return value and secondly by calling the xarCurrentErrorType function.
The Xaraya Exception Handling System provides useful functions to deal with exceptions. Their signatures are:
void xarExceptionSet($major, $exception_id, $param = NULL); integer xarCurrentErrorType(); string xarExceptionId(); object xarExceptionValue(); void xarExceptionFree();
xarCurrentErrorType allows the caller to establish whether an exception was raised, and to get the type of raised exception. The major XAR_NO_EXCEPTION identifies the state in which no exception was raised.
xarExceptionSet allows a function to raise an exception. The caller must supply a value for the major parameter. The major parameter can have one of the values XAR_NO_EXCEPTION, XAR_USER_EXCEPTION, or XAR_SYSTEM_EXCEPTION. The value of the major parameter constrains the other parameters in the call as follows:
If the major parameter has the value XAR_NO_EXCEPTION, this is a normal outcome
to the operation. In this case, both exception_id and param must be NULL. Note that it is not necessary to invoke xarExceptionSet to indicate a normal outcome; it is the default behavior if the method simply returns.
For any other value of major it specifies either a user-defined or system
exception. The exception_id parameter is the ID representing the exception type. If the exception is declared to have members, the param parameter must be the exception struct (PHP class) containing the members. If the exception has no members, param must be NULL.
Replaced with xarCurrentErrorType commencing in Version 0.9.8
xarExceptionId returns the string identifying the exception. The character string contains the ID for the exception (its PHP class name). If invoked when no exception was raised a void value is returned.
xarExceptionValue returns an object corresponding to this exception. If invoked when no exception or an exception for which there is no associated information was raised, a void value is returned.
xarExceptionFree makes a reset of current exception status, it's a shortcut for xarExceptionSet (XAR_NO_EXCEPTION, NULL, NULL). You must always call this function when you handle a catched exception or equivalently you don't throw the exception back to the callers chain.
To get an overview on their usage consider the following example:
class ?MyException { var $msg; } function ?MyModule_userapi_?MyFunc() { /* Called */ /* ... */ } ?... /* Caller */ /* ... */ $res = xarModAPIFunc('?MyModule', 'user', '?MyFunc'); if (!isset($res) && xarCurrentErrorType() != XAR_NO_EXCEPTION) { // Got an exception switch (xarCurrentErrorType()) { case XAR_USER_EXCEPTION: if (xarExceptionId() == '?MyException') { $value = xarExceptionValue(); die("Caught ?MyException, msg: ".$value->msg); } break; case XAR_SYSTEM_EXCEPTION: die("Caught system exception: ".xarExceptionId()); break; } } /* ... */
An important thing to take care of is the throw back mechanism. Even if with this proposed solution there is not a break in the program flow when an exception is raised, the Exceptions Handling System allows you to apply the concept of throwing back an exception. And it's also very simple to do that, you've only to return with a void value after you catch an exception. Consider the following example:
function foo() { $res = xarModAPIFunc('?MyModule', 'user', '?MyFunc'); if (!isset($res) && xarCurrentErrorType() != XAR_NO_EXCEPTION) { // Got an exception, throw it back return; } } function bar() { $res = foo(); if (!isset($res) && xarCurrentErrorType() != XAR_NO_EXCEPTION) { // Got an exception // Real exception handling switch (xarCurrentErrorType()) { case XAR_USER_EXCEPTION: if (xarExceptionId() == '?MyException') { $value = xarExceptionValue(); die("Caught ?MyException, msg: ".$value->msg); } break; case XAR_SYSTEM_EXCEPTION: die("Caught system exception: ".xarExceptionId()); break; } } }
As you can see in the above example we're delegating to another piece of code the real exception handling.
To best integrate the Exceptions Handling System into Xaraya we need to define a superset of well known exceptions called System Exceptions and to make the Xaraya APIs compatible with Exceptions Handling System. Modifications to APIs involve the usage of System Exceptions. To get an example of what is a System Exception consider the case in which you're calling an API with a non existent user id. In that case you're violating the Xaraya integrity, so it makes sense to raise an exception of type ID_NOT_EXISTS internally in the API function. For another example you could recall the xarModAPIFunc function. Its purpose is to call an API module function and returns the outcome value of the called API module function. But what's happen if xarModAPIFunc can't call the function you've indicated. As you can read in Xaraya API Command Reference, xarModAPIFunc will return false if the module function does not exist or void for an internal error. By doing so xarModAPIFunc vincolates your module API functions to never return void or false because the caller can't distinguish these values from an error condition in xarModAPIFunc. In the other hand if xarModAPIFunc could raise exceptions your module API functions could return false and void as well, since you're allowed to discover error conditions with the Exception Handling System and not by relaying on return value. As you can see there are many advantages in exceptions but we must keep the Xaraya API as backward compatible as possible. Consider also that exceptions go well not for all error conditions, if you're doing that probably you're wrong. Boolean functions go very well in many cases, and most of Xaraya API functions can indicate particular errors with the false return value. Exceptions have to be used when there's a real needing of them, and not as a replacement for the false return value. The changes that have to be done in Xaraya API must be minimals, and relay only on System Exceptions.
The Exceptions Handling System need to be closely integrated with Xaraya. To achieve this goal the well known System Exceptions take care of Xaraya architecture, so we will refer to them as Xaraya System Exceptions. A system exception always contains as exception value a PHP class so defined:
class ?SystemException { var $message; }
where the message member is a language-sensitive error message associated with the particular system exception.
Here is a list of Xaraya System Exceptions:
TBD: extend this list
Here is a list of modifications that should occur on current version of Xaraya API. Every modification exposed here is described by three fields:
api: xarConfigGetVar changes: no changes on return value, add code to raise exceptions exceptions: ID_NOT_EXIST, DATABASE_ERROR
api: xarConfigSetVar changes: change to return void on error, add code to raise exceptions exceptions: DATABASE_ERROR
api: xarConfigDelVar changes: to be done
api: xarDBGetConn changes: no changes
api: xarDBGetTables changes: no changes
api: xarVarCleanFromInput changes: no changes on return value, add code to raise exceptions exceptions: ID_NOT_EXIST
api: xarVarPrepForDisplay changes: no changes
api: xarVarPrepHTMLDisplay changes: no changes, add code to throw back exceptions
api: xarVarPrepForStore changes: no changes
api: xarVarPrepForOS changes: no changes
api: xarVarCensor changes: no changes, add code to throw back exceptions
api: xarVarValidate changes: no changes
api: xarGetBaseURI changes: no changes
api: xarGetBaseURL changes: no changes
api: xarRedirect changes: no changes
api: xarBlockShow changes: no changes, add code to throw back exceptions
api: xarBlockLoad changes: no changes, add code to throw back exceptions
api: xarBlockGetInfo changes: change to return void on error, add code to raise exceptions exceptions: DATABASE_ERROR
api: xarModGetVar changes: change to return void on error, add code to raise exceptions exceptions: DATABASE_ERROR, BAD_PARAM
api: xarModSetVar changes: change to return void on error, add code to raise exceptions exceptions: DATABASE_ERROR, BAD_PARAM
api: xarModDelVar changes: change to return void on error, add code to raise exceptions exceptions: DATABASE_ERROR, BAD_PARAM
api: xarModGetIDFromName changes: change to return void on error, add code to raise exceptions exceptions: DATABASE_ERROR, BAD_PARAM
api: xarModGetInfo changes: change to return void on error, add code to raise exceptions exceptions: DATABASE_ERROR, BAD_PARAM
api: xarModGetUserMods changes: change to return void on error, add code to raise exceptions exceptions: DATABASE_ERROR
api: xarModGetAdminMods changes: change to return void on error, add code to raise exceptions exceptions: DATABASE_ERROR
api: xarModAPILoad changes: change to return void on error, add code to raise exceptions exceptions: DATABASE_ERROR, BAD_PARAM, MODULE_NOT_EXIST, MODULE_FILE_NOT_EXIST
api: xarModDBInfoLoad changes: change to return void on error, add code to raise exceptions exceptions: DATABASE_ERROR, BAD_PARAM, MODULE_NOT_EXIST
api: xarModLoad changes: change to return void on error, add code to raise exceptions exceptions: DATABASE_ERROR, BAD_PARAM, MODULE_NOT_EXIST, MODULE_FILE_NOT_EXIST
api: xarModAPIFunc changes: change to return void on error, add code to raise exceptions exceptions: BAD_PARAM, MODULE_FUNC_NOT_EXIST
api: xarModFunc changes: change to return void on error, add code to raise exceptions exceptions: BAD_PARAM, MODULE_FUNC_NOT_EXIST
api: xarModURL changes: change to return void on error, add code to raise exceptions exceptions: BAD_PARAM
api: xarModAvailable changes: change to return void on error, add code to raise exceptions exceptions: DATABASE_ERROR, BAD_PARAM
api: xarModGetName changes: to be done
api: xarModRegisterHook changes: change to return void on error, add code to raise exceptions exceptions: DATABASE_ERROR
api: xarModUnregisterHook changes: change to return void on error, add code to raise exceptions exceptions: DATABASE_ERROR
api: xarModCallHooks changes: change to return void on error, add code to raise exceptions exceptions: DATABASE_ERROR
api: xarSecAddSchema changes: no changes
api: xarSecAuthAction changes: change to return void on error, add code to raise exceptions exceptions: DATABASE_ERROR
api: xarSecGetAuthInfo changes: change to return void on error, add code to raise exceptions exceptions: DATABASE_ERROR
api: xarSecGetLevel changes: no changes
api: xarSecGenAuthKey changes: no changes
api: xarSecConfirmAuthKey changes: no changes
api: xarSessionGetVar changes: no changes
api: xarSessionSetVar changes: no changes
api: xarSessionDelVar changes: no changes
api: xarUserLogIn changes: change to return void on error, add code to raise exceptions exceptions: DATABASE_ERROR, BAD_PARAM
api: xarUserLogOut changes: change to return void on error, add code to raise exceptions exceptions: DATABASE_ERROR
api: xarUserLoggedIn changes: no changes
api: xarUserGetTheme changes: no changes
api: xarUserGetLang changes: no changes
api: xarUserGetVar changes: change to return void on error, add code to raise exceptions exceptions: BAD_PARAM, ID_NOT_EXIST, NO_PERMISSION
api: xarUserSetVar changes: change to return void on error, add code to raise exceptions exceptions: BAD_PARAM, ID_NOT_EXIST, NO_PERMISSION
api: xarUserValidateVar changes: change to return void on error, add code to raise exceptions exceptions: BAD_PARAM, ID_NOT_EXIST
0.1 (May 8, 2002)
Extended Xaraya System Exceptions section.
Added Xaraya API changes section.
pre-0.1 (May 5, 2002)
Initial Version by Marco Canini <marco.canini@postnuke.com>