diff --git a/README.md b/README.md index 8bed47e..95d24ad 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ ## Usage -Installing the *Asplode* error handler can be achieved by a single statement: +The *Asplode* error handler can be installed with a single statement: ```php Eloquent\Asplode\Asplode::install(); @@ -21,49 +21,63 @@ Eloquent\Asplode\Asplode::install(); ## What does *Asplode* do? -*Asplode* is very simple library that sets up an [error handler] to throw -[ErrorException] exceptions instead of using the default PHP error handler. This -method of error handling has proven to be extremely effective, and similar -systems are in use across major PHP frameworks such as [Symfony]. +*Asplode* is a very simple PHP [error handler] implementation that throws +[ErrorException] exceptions instead of using the default PHP error handling +behaviour. This means that all non-fatal runtime errors are presented to the +developer in the form of an exception. It also means that any unhandled errors +are delivered to a single point, the global exception handler. ## Why use *Asplode*? -Exceptions offer a much more consistent way to handle errors. In modern PHP -development it is generally considered best-practice to use an exception rather -than a legacy-style error. +Developers need the ability to decide how their code behaves when an error +occurs. Exceptions offer the only truly consistent way to report and recover +from errors in PHP. -*Asplode* offers a hassle-free way to improve the error handling in a PHP -project. It also provides a consistent error handling implementation across -any project or library it's used in, allowing for easier integration. +This method of handling errors has proven to be extremely effective. Similar +strategies are used in major PHP frameworks such as [Symfony]. + +*Asplode* is a standalone implementation that can be used for any project. ## Fatal error handling -*Asplode* provides a simple way to improve the handling of fatal errors. Whilst -fatals can't really be handled in the same way as regular errors, if a global -exception handler is installed, it can be passed an Exception representing the -fatal error just before PHP execution completes. This allows developers to -gracefully inform the user of fatal errors before shutdown occurs. +While it's not feasible to *recover* from fatal PHP errors, it is possible to +*report* fatal errors in the same manner as uncaught exceptions. + +With *Asplode*, fatal errors cause a synthesized exception representing the +fatal error to be passed to the global exception handler. This allows developers +to gracefully inform the user of fatal errors just before the PHP interpreter is +shut down. + +The *Asplode* fatal error handler is installed by default, but is only activated +if a global exception handler is installed. ```php -// a global exception handler must be in place: set_exception_handler( function (Exception $e) { echo $e->getMessage(); } ); -Eloquent\Asplode\Asplode::installFatalHandler(); +Eloquent\Asplode\Asplode::install(); ``` +To use *Asplode* without the fatal error handler, use `installErrorHandler()` +instead of `Asplode::install()`. To use only the fatal error handler, use +`installFatalHandler()`. + +Please note that because the PHP autoloader will not function during a fatal +error, and as such custom exception handlers should explicitly load their +dependencies where possible. + ## Asserting that the current error handler is compatible -Code that assumes the use of *Asplode* will not work as expected unless the -right type of error handler is installed. For example, code expecting to catch -an `ErrorException` on failure will have unpredictable results if the installed +Code that assumes the use of *Asplode* may not work as expected unless the right +type of error handler is installed. For example, code expecting to catch an +`ErrorException` on failure will have unpredictable results if the installed error handler does not throw `ErrorException` instances. To ensure that a correctly configured error handler is installed, *Asplode* -provides the `Asplode::assertCompatibleHandler()` method: +provides the `Asplode::assertCompatibleHandler()` method. ```php use Eloquent\Asplode\Asplode; @@ -76,64 +90,27 @@ try { } ``` -## Executing legacy code - -Sometimes it is unavoidable to work with code that uses bad practices. For -example, a old PHP library might be quite functional and useful, but it may not -anticipate exceptions being thrown when an error occurs. - -*Asplode*'s handler stacks both implement an `executeWith()` method that allows -code to be executed with a different handler than the one currently installed. -This method pops all current handlers off the stack temporarily, installs the -specified handler (if one is provided), executes the supplied callback, restores -the handler stack, and returns the result of the callback's execution. - -```php -use Eloquent\Asplode\HandlerStack\ErrorHandlerStack; - -$stack = new ErrorHandlerStack; - -$result = $stack->executeWith( - function () { - // this code will be executed under the default handler - } -); - -$result = $stack->executeWith( - function () { - // this code will be executed under the supplied handler - }, - 'errorHandlerFunctionName' -); - -$result = $stack->executeWith( - function () { - // this code will be executed under the supplied handler - }, - function ($severity, $message, $path, $lineNumber) { - // handle the error - } -); -``` +A *compatible* error handler is any handler that throws `ErrorException` +exceptions. It does not need to be the implementation provided by *Asplode*. ## Managing PHP's handler stacks -PHP's error handlers and exception handlers function roughly as a [stack]. -However, the implementation is quite limited, and frankly, bad. *Asplode* -includes classes to aid in management of these stacks, which can be harnessed to -manage error handling in a simple, and flexible manner. +PHP's error and exception handlers approximate the behaviour of a [stack]. +However, the interface for manipulating the stack is limited, and quite frankly, +poorly implemented. -The two classes responsible for management of these stacks are +*Asplode* includes two classes to aid in management of these stacks, [ErrorHandlerStack] and [ExceptionHandlerStack]. Both implement -[HandlerStackInterface]. These classes do not require the use of the *Asplode* -handler, they can be used in a standalone manner to manage the handler stacks. +[HandlerStackInterface] which provides a familiar interface for working with +stacks. These classes do not require the use of the *Asplode* handler; they can +be used in a standalone manner to manage the handler stacks. ## Migrating existing code to work with Asplode When the *Asplode* error handler is installed, the [error_reporting] setting -will no longer have any effect. Notices, warnings, and errors will all throw an -exception. Deprecation notices will not throw an exception, but will still be -logged, as long as PHP's error logging is correctly configured. +will no longer have any effect. Notices, warnings, and errors will all result in +an exception being thrown. Deprecation notices will not throw an exception, but +will still be logged provided that PHP is configured to do so. Code that has been written to handle legacy-style PHP errors will most likely need to be re-written. As an example, this type of logic: @@ -146,7 +123,7 @@ if ($fp === false) { } ``` -would need to be replaced with something like: +would need to be rewritten to to handle exceptions: ```php try { @@ -156,12 +133,56 @@ try { } ``` -It's important to note that PHP can be very inconsistent in the way it handles +It's important to note that PHP can be very inconsistent in the way it reports error conditions. In some cases functions will simply return a boolean false -when an error occurs; or it may have even stranger, less standard behaviour. +when an error occurs, others require the developer to call additional functions +to check for errors, while others still maybe have entirely non-standard +behaviour. *Asplode* does not free the developer from the responsibility of reading the PHP -documentation, or making sure that they account for all possible outcomes. +documentation, or making sure that they account for all possible error +conditions. + +## Executing legacy code + +Sometimes working with code that uses bad practices is unavoidable. A legacy PHP +library might be perfectly functional and useful, but it may not anticipate +exceptions being thrown when an error occurs. + +*Asplode*'s exception and error handler stacks both implement an `executeWith()` +method that allows code to be executed with a different handler than the one +currently installed. This method pops all current handlers off the stack +temporarily, installs the specified handler (if one is provided) and executes +the supplied callback. The original handler is restored after the callback is +executed. + +```php +use Eloquent\Asplode\HandlerStack\ErrorHandlerStack; + +$stack = new ErrorHandlerStack; + +$result = $stack->executeWith( + function () { + // this code will be executed under the default handler + } +); + +$result = $stack->executeWith( + function () { + // this code will be executed under the supplied handler + }, + 'errorHandlerFunctionName' +); + +$result = $stack->executeWith( + function () { + // this code will be executed under the supplied handler + }, + function ($severity, $message, $path, $lineNumber) { + // handle the error + } +); +```