Nice solution found in Zend Framework 2:
/**
* ErrorHandler that can be used to catch internal PHP errors
* and convert to an ErrorException instance.
*/
abstract class ErrorHandler
{
/**
* Active stack
*
* @var array
*/
protected static $stack = array[];
/**
* Check if this error handler is active
*
* @return bool
*/
public static function started[]
{
return [bool] static::getNestedLevel[];
}
/**
* Get the current nested level
*
* @return int
*/
public static function getNestedLevel[]
{
return count[static::$stack];
}
/**
* Starting the error handler
*
* @param int $errorLevel
*/
public static function start[$errorLevel = \E_WARNING]
{
if [!static::$stack] {
set_error_handler[array[get_called_class[], 'addError'], $errorLevel];
}
static::$stack[] = null;
}
/**
* Stopping the error handler
*
* @param bool $throw Throw the ErrorException if any
* @return null|ErrorException
* @throws ErrorException If an error has been catched and $throw is true
*/
public static function stop[$throw = false]
{
$errorException = null;
if [static::$stack] {
$errorException = array_pop[static::$stack];
if [!static::$stack] {
restore_error_handler[];
}
if [$errorException && $throw] {
throw $errorException;
}
}
return $errorException;
}
/**
* Stop all active handler
*
* @return void
*/
public static function clean[]
{
if [static::$stack] {
restore_error_handler[];
}
static::$stack = array[];
}
/**
* Add an error to the stack
*
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param int $errline
* @return void
*/
public static function addError[$errno, $errstr = '', $errfile = '', $errline = 0]
{
$stack = & static::$stack[count[static::$stack] - 1];
$stack = new ErrorException[$errstr, 0, $errno, $errfile, $errline, $stack];
}
}
This class allows you to start the specific ErrorHandler
sometimes if you need it. And then you can also stop the Handler.
Use this class e.g. like this:
ErrorHandler::start[E_WARNING];
$return = call_function_raises_E_WARNING[];
if [$innerException = ErrorHandler::stop[]] {
throw new Exception['Special Exception Text', 0, $innerException];
}
// or
ErrorHandler::stop[true]; // directly throws an Exception;
Link to the full class code:
//github.com/zendframework/zf2/blob/master/library/Zend/Stdlib/ErrorHandler.php
A maybe better solution is that one from Monolog:
Link to the full class code:
//github.com/Seldaek/monolog/blob/master/src/Monolog/ErrorHandler.php
It can also handle FATAL_ERRORS using the register_shutdown_function
function. According to this class a FATAL_ERROR is one of the
following array[E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR]
.
class ErrorHandler
{
// [...]
public function registerExceptionHandler[$level = null, $callPrevious = true]
{
$prev = set_exception_handler[array[$this, 'handleException']];
$this->uncaughtExceptionLevel = $level;
if [$callPrevious && $prev] {
$this->previousExceptionHandler = $prev;
}
}
public function registerErrorHandler[array $levelMap = array[], $callPrevious = true, $errorTypes = -1]
{
$prev = set_error_handler[array[$this, 'handleError'], $errorTypes];
$this->errorLevelMap = array_replace[$this->defaultErrorLevelMap[], $levelMap];
if [$callPrevious] {
$this->previousErrorHandler = $prev ?: true;
}
}
public function registerFatalHandler[$level = null, $reservedMemorySize = 20]
{
register_shutdown_function[array[$this, 'handleFatalError']];
$this->reservedMemory = str_repeat[' ', 1024 * $reservedMemorySize];
$this->fatalLevel = $level;
}
// [...]
}
The new interface
While PHP 7 provides both Error and Exception classes, let’s check the Throwable interface first. Both Error and Exception classes implement Throwable interface – it's a basis for any object that can be thrown via throw statement. It only has one exception to notice, it cannot be implemented in userland classes directly, but only through extending the Exception class. Also, it provides a single point for catching both types of error in a single statement:
Conclusion
Since the first introduction of exception handling to PHP, many years have passed until we ended up with much more solid and matured exceptional handling that Java had, quite frankly for ages. Error handling in PHP 7 received much attention making it solid good, opening space for future improvements if we actually from today's perspective need one.