Skip to content

Latest commit

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

ordinary/error

PHP error and exception handler management.

Overview

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.

Installation

composer require ordinary/error

Quick start

useOrdinary\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);

Smart registration

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 $framework

Pass chainCurrent: true to wrap any previously registered PHP handler and keep it in the chain:

ErrorHandler::register($handler, chainCurrent: true);

Matchers

Matchers filter which throwables reach a handler.

MatcherDescription
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)),
);

Built-in handlers

LogHandler

Logs each throwable through a PSR-3 logger. PHP error severity levels are mapped to PSR-3 levels automatically:

PHP severityPSR-3 level
E_ERROR, E_USER_ERROR, E_CORE_ERROR, E_COMPILE_ERRORcritical
E_RECOVERABLE_ERRORerror
E_WARNING, E_USER_WARNING, E_CORE_WARNING, E_COMPILE_WARNINGwarning
E_NOTICE, E_USER_NOTICEnotice
E_DEPRECATED, E_USER_DEPRECATED, E_STRICTinfo
Other throwables or unmapped severities$defaultLevel (default: error)
useOrdinary\Error\Handler\LogHandler;
usePsr\Log\LogLevel;
$handler->add(newLogHandler($logger, defaultLevel: LogLevel::CRITICAL));

CallableHandler

Wraps any callable(\Throwable): void as a handler:

useOrdinary\Error\CallableHandler;
$handler->add(newCallableHandler(function (\Throwable$t): void {
// custom logic
}));

NativeErrorHandlerAdapter

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));

Async dispatch

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.

Handler failure handling

When an asynchronously dispatched handler throws, the exception is forwarded to a HandlerFailureHandlerInterface:

ImplementationBehaviour
ErrorLogFailureHandlerWrites to PHP's error log (default)
NoOpFailureHandlerSilently discards failures
StderrFailureHandlerWrites to STDERR
useOrdinary\Error\ExceptionHandler;
useOrdinary\Error\FailureHandler\StderrFailureHandler;
$handler = newExceptionHandler(onFailure: newStderrFailureHandler());

Error suppression

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.

About

PHP error and exception handler management for OrdinaryPHP.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages