PHP error and exception handler management.
This package provides two invokable handler classes — ErrorHandler and ExceptionHandler — that can be registered with PHP's set_error_handler() and set_exception_handler(). Each accepts multiple handlers and optional matchers to route only matching throwables to each handler.
PHP errors are always converted to ErrorException before dispatch, so a single ThrowableHandlerInterface implementation handles both errors and exceptions without duplicated logic.
composer require ordinary/erroruseOrdinary\Error\ErrorHandler;
useOrdinary\Error\ExceptionHandler;
useOrdinary\Error\Handler\LogHandler;
useOrdinary\Error\Matcher\IsErrorSeverity;
useOrdinary\Error\Matcher\IsInstanceOf;
// Register an error handler that logs warnings and notices$errorHandler = newErrorHandler();
$errorHandler->add(
newLogHandler($logger),
newIsErrorSeverity(E_WARNING, E_NOTICE, E_DEPRECATED),
);
ErrorHandler::register($errorHandler);
// Register an exception handler for uncaught throwables$exceptionHandler = newExceptionHandler();
$exceptionHandler->add(newLogHandler($logger));
ExceptionHandler::register($exceptionHandler);Calling register() when a handler of the same type is already registered appends the new handlers to the existing instance rather than replacing it. This lets a framework and plugins each contribute handlers independently:
// Framework registers first$framework = newErrorHandler();
$framework->add(newLogHandler($frameworkLogger));
ErrorHandler::register($framework);
// Plugin registers later — handlers are merged into $framework$plugin = newErrorHandler();
$plugin->add(newLogHandler($pluginLogger));
$effective = ErrorHandler::register($plugin); // returns $frameworkPass chainCurrent: true to wrap any previously registered PHP handler and keep it in the chain:
ErrorHandler::register($handler, chainCurrent: true);Matchers filter which throwables reach a handler.
| Matcher | Description |
|---|---|
IsErrorSeverity(int ...$severities) | Matches \ErrorException whose severity overlaps the given flags |
IsInstanceOf(string $class) | Matches throwables that are instances of a class or interface |
IsAll(matcher, ...) | All matchers must pass (AND) |
IsAny(matcher, ...) | Any matcher must pass (OR) |
IsNot(matcher) | Inverts a matcher |
CallableMatcher(callable) | Wraps a callable(\Throwable): bool |
useOrdinary\Error\Matcher\IsAll;
useOrdinary\Error\Matcher\IsErrorSeverity;
useOrdinary\Error\Matcher\IsNot;
// Only errors that are NOT deprecated notices$handler->add(
newLogHandler($logger),
newIsNot(newIsErrorSeverity(E_DEPRECATED, E_USER_DEPRECATED)),
);Logs each throwable through a PSR-3 logger. PHP error severity levels are mapped to PSR-3 levels automatically:
| PHP severity | PSR-3 level |
|---|---|
E_ERROR, E_USER_ERROR, E_CORE_ERROR, E_COMPILE_ERROR | critical |
E_RECOVERABLE_ERROR | error |
E_WARNING, E_USER_WARNING, E_CORE_WARNING, E_COMPILE_WARNING | warning |
E_NOTICE, E_USER_NOTICE | notice |
E_DEPRECATED, E_USER_DEPRECATED, E_STRICT | info |
| Other throwables or unmapped severities | $defaultLevel (default: error) |
useOrdinary\Error\Handler\LogHandler;
usePsr\Log\LogLevel;
$handler->add(newLogHandler($logger, defaultLevel: LogLevel::CRITICAL));Wraps any callable(\Throwable): void as a handler:
useOrdinary\Error\CallableHandler;
$handler->add(newCallableHandler(function (\Throwable$t): void {
// custom logic
}));Adapts a native set_error_handler callback (signature (int, string, string, int): bool) for use inside an ErrorHandler:
useOrdinary\Error\NativeErrorHandlerAdapter;
$handler->add(newNativeErrorHandlerAdapter($existingCallback));Both ErrorHandler and ExceptionHandler accept an optional $dispatcher closure. Non-synchronous handlers are passed to the dispatcher as zero-argument operations:
useOrdinary\Error\ErrorHandler;
$handler = newErrorHandler(
dispatcher: fn(\Closure$op) => $eventLoop->queue($op),
);Handlers implementing SynchronousHandlerInterface bypass the dispatcher and always run immediately.
When an asynchronously dispatched handler throws, the exception is forwarded to a HandlerFailureHandlerInterface:
| Implementation | Behaviour |
|---|---|
ErrorLogFailureHandler | Writes to PHP's error log (default) |
NoOpFailureHandler | Silently discards failures |
StderrFailureHandler | Writes to STDERR |
useOrdinary\Error\ExceptionHandler;
useOrdinary\Error\FailureHandler\StderrFailureHandler;
$handler = newExceptionHandler(onFailure: newStderrFailureHandler());ErrorHandler respects the @ error-suppression operator: errors that fall outside the current error_reporting() mask return false, allowing PHP's built-in handler to process them normally.