A Throwable catcher and error handling library for PHP
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
3.2 KiB

<?php
/**
* @license MIT
* Copyright 2022 Dustin Wilson, et al.
* See LICENSE and AUTHORS files for details
*/
declare(strict_types=1);
namespace Mensbeam\Framework;
use Mensbeam\Framework\Catcher\{
ThrowableController,
Handler
};
class Catcher {
/**
* Array of handlers the exceptions are passed to
*
* @var Handler[]
*/
protected array $handlers = [];
protected array $handlerClasses = [];
/** Flag set when the shutdown handler is run */
protected bool $isShuttingDown = false;
protected Map $results;
public function __construct(string ...$handlerClasses) {
$this->handlerClasses = $handlerClasses;
$this->results = new Map();
set_error_handler([ $this, 'handleError' ]);
set_exception_handler([ $this, 'handleThrowable' ]);
register_shutdown_function([ $this, 'handleShutdown' ]);
}
/**
* Converts regular errors into throwable Errors for easier handling; meant to be
* used with set_error_handler.
*
* @internal
*/
public function handleError(int $code, string $message, ?string $file = null, ?int $line = null): bool {
if ($code !== 0 && error_reporting()) {
$error = new Error($message, $code, $file, $line);
if ($this->isShuttingDown) {
throw $error;
} else {
$this->handleThrowable($error);
}
return true;
}
return false;
}
/**
* Handles both Exceptions and Errors; meant to be used with set_exception_handler.
*
* @internal
*/
public function handleThrowable(\Throwable $throwable): void {
$controller = new ThrowableController($throwable);
foreach ($this->handlerClasses as $h) {
$handler = $h::create($controller);
$code = $handler->getOutputCode();
if ($code & Handler::OUTPUT_NOW) {
$handler->output();
} else {
$this->handlers[] = $handler;
}
if ($code & Handler::CONTINUE) {
break;
}
}
/*if ($this->isShuttingDown || $throwable instanceof \Exception || in_array($throwable->getCode(), [ \E_ERROR, \E_PARSE, \E_CORE_ERROR, \E_COMPILE_ERROR, \E_USER_ERROR ]) {
}*/
if (
$this->isShuttingDown ||
$throwable instanceof \Exception ||
in_array($throwable->getCode(), [ \E_ERROR, \E_PARSE, \E_CORE_ERROR, \E_COMPILE_ERROR, \E_USER_ERROR ])
) {
exit($throwable->getCode());
}
}
/**
* Handles shutdowns, passes all possible built-in error codes to the error handler.
*
* @internal
*/
public function handleShutdown() {
$this->isShuttingDown = true;
if (error_get_last() && in_array($error['type'], [ \E_ERROR, \E_PARSE, \E_CORE_ERROR, \E_CORE_WARNING, \E_COMPILE_ERROR, \E_COMPILE_WARNING ])) {
$this->handleError($error['type'], $error['message'], $error['file'], $error['line']);
}
}
public static function isHTTPRequest() {
return (\PHP_SAPI !== 'cli' && isset($_SERVER['REQUEST_URI']) && isset($_SERVER['REQUEST_METHOD']));
}
}