Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Yii Error Handler Change Log

## 5.0 under development

- Chg #121: Make logger in ErrorHandler optional (@olegbaturin)
- Chg #144: Mark ErrorException and UserException as final (@olegbaturin)
- Chg #146: Remove deprecated `Yiisoft\ErrorHandler\Factory\ThrowableResponseFactory` (@olegbaturin)
- Chg #157: Rename `Yiisoft\ErrorHandler\ThrowableResponseFactory` to `Yiisoft\ErrorHandler\ThrowableResponseAction` (@olegbaturin)
- Chg #157: Change parameters order in `ThrowableResponseActionInterface` (@olegbaturin)

## 4.3.1 under development

- no changes in this release.
Expand Down
26 changes: 23 additions & 3 deletions config/di-web.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,36 @@

declare(strict_types=1);

use Yiisoft\ErrorHandler\Factory\ThrowableResponseFactory;
use Psr\Container\ContainerInterface;
use Yiisoft\Definitions\DynamicReference;
use Yiisoft\Definitions\Reference;
use Yiisoft\ErrorHandler\Middleware\ErrorCatcher;
use Yiisoft\ErrorHandler\Renderer\HtmlRenderer;
use Yiisoft\ErrorHandler\RendererProvider\CompositeRendererProvider;
use Yiisoft\ErrorHandler\RendererProvider\ContentTypeRendererProvider;
use Yiisoft\ErrorHandler\RendererProvider\HeadRendererProvider;
use Yiisoft\ErrorHandler\ThrowableRendererInterface;
use Yiisoft\ErrorHandler\ThrowableResponseFactoryInterface;
use Yiisoft\ErrorHandler\ThrowableResponseAction;

/**
* @var array $params
*/

return [
ThrowableRendererInterface::class => HtmlRenderer::class,
ThrowableResponseFactoryInterface::class => ThrowableResponseFactory::class,
ErrorCatcher::class => [
'__construct()' => [
'throwableResponseAction' => Reference::to(ThrowableResponseAction::class),
],
],
ThrowableResponseAction::class => [
'__construct()' => [
'rendererProvider' => DynamicReference::to(
static fn(ContainerInterface $container) => new CompositeRendererProvider(
new HeadRendererProvider(),
new ContentTypeRendererProvider($container),
)
),
],
],
];
6 changes: 3 additions & 3 deletions src/ErrorHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,16 @@
private bool $initialized = false;

/**
* @param LoggerInterface $logger Logger to write errors to.
* @param ThrowableRendererInterface $defaultRenderer Default throwable renderer.
* @param LoggerInterface|null $logger Logger to write errors to.
* @param EventDispatcherInterface|null $eventDispatcher Event dispatcher for error events.
* @param int $exitShutdownHandlerDepth Depth of the exit() shutdown handler to ensure it's executed last.
*/
public function __construct(
private readonly LoggerInterface $logger,
private readonly ThrowableRendererInterface $defaultRenderer,
private readonly ?LoggerInterface $logger = null,
private readonly ?EventDispatcherInterface $eventDispatcher = null,
private readonly int $exitShutdownHandlerDepth = 2

Check warning on line 53 in src/ErrorHandler.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "IncrementInteger": --- Original +++ New @@ @@ * @param EventDispatcherInterface|null $eventDispatcher Event dispatcher for error events. * @param int $exitShutdownHandlerDepth Depth of the exit() shutdown handler to ensure it's executed last. */ - public function __construct(private readonly ThrowableRendererInterface $defaultRenderer, private readonly ?LoggerInterface $logger = null, private readonly ?EventDispatcherInterface $eventDispatcher = null, private readonly int $exitShutdownHandlerDepth = 2) + public function __construct(private readonly ThrowableRendererInterface $defaultRenderer, private readonly ?LoggerInterface $logger = null, private readonly ?EventDispatcherInterface $eventDispatcher = null, private readonly int $exitShutdownHandlerDepth = 3) { } /**

Check warning on line 53 in src/ErrorHandler.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "DecrementInteger": --- Original +++ New @@ @@ * @param EventDispatcherInterface|null $eventDispatcher Event dispatcher for error events. * @param int $exitShutdownHandlerDepth Depth of the exit() shutdown handler to ensure it's executed last. */ - public function __construct(private readonly ThrowableRendererInterface $defaultRenderer, private readonly ?LoggerInterface $logger = null, private readonly ?EventDispatcherInterface $eventDispatcher = null, private readonly int $exitShutdownHandlerDepth = 2) + public function __construct(private readonly ThrowableRendererInterface $defaultRenderer, private readonly ?LoggerInterface $logger = null, private readonly ?EventDispatcherInterface $eventDispatcher = null, private readonly int $exitShutdownHandlerDepth = 1) { } /**
) {
}

Expand All @@ -68,7 +68,7 @@
$renderer ??= $this->defaultRenderer;

try {
$this->logger->error($t->getMessage(), ['throwable' => $t]);
$this->logger?->error($t->getMessage(), ['throwable' => $t]);

Check warning on line 71 in src/ErrorHandler.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "ArrayItemRemoval": --- Original +++ New @@ @@ { $renderer ??= $this->defaultRenderer; try { - $this->logger?->error($t->getMessage(), ['throwable' => $t]); + $this->logger?->error($t->getMessage(), []); return $this->debug ? $renderer->renderVerbose($t, $request) : $renderer->render($t, $request); } catch (Throwable $t) { return new ErrorData((string) $t);
return $this->debug ? $renderer->renderVerbose($t, $request) : $renderer->render($t, $request);
} catch (Throwable $t) {
return new ErrorData((string) $t);
Expand Down Expand Up @@ -108,14 +108,14 @@
return;
}

if ($this->memoryReserveSize > 0) {

Check warning on line 111 in src/ErrorHandler.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "GreaterThanNegotiation": --- Original +++ New @@ @@ if ($this->enabled) { return; } - if ($this->memoryReserveSize > 0) { + if ($this->memoryReserveSize <= 0) { $this->memoryReserve = str_repeat('x', $this->memoryReserveSize); } $this->initializeOnce();

Check warning on line 111 in src/ErrorHandler.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "GreaterThan": --- Original +++ New @@ @@ if ($this->enabled) { return; } - if ($this->memoryReserveSize > 0) { + if ($this->memoryReserveSize >= 0) { $this->memoryReserve = str_repeat('x', $this->memoryReserveSize); } $this->initializeOnce();
$this->memoryReserve = str_repeat('x', $this->memoryReserveSize);
}

$this->initializeOnce();

Check warning on line 115 in src/ErrorHandler.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "MethodCallRemoval": --- Original +++ New @@ @@ if ($this->memoryReserveSize > 0) { $this->memoryReserve = str_repeat('x', $this->memoryReserveSize); } - $this->initializeOnce(); + // Handles throwable that isn't caught otherwise, echo output and exit. set_exception_handler(function (Throwable $t) : void { if (!$this->enabled) {

// Handles throwable that isn't caught otherwise, echo output and exit.
set_exception_handler(function (Throwable $t): void {

Check warning on line 118 in src/ErrorHandler.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "FunctionCallRemoval": --- Original +++ New @@ @@ $this->memoryReserve = str_repeat('x', $this->memoryReserveSize); } $this->initializeOnce(); - // Handles throwable that isn't caught otherwise, echo output and exit. - set_exception_handler(function (Throwable $t) : void { - if (!$this->enabled) { - return; - } - $this->renderThrowableAndTerminate($t); - }); + // Handles PHP execution errors such as warnings and notices. set_error_handler(function (int $severity, string $message, string $file, int $line) : bool { if (!$this->enabled) {
if (!$this->enabled) {
return;
}
Expand All @@ -129,12 +129,12 @@
return false;
}

if (!(error_reporting() & $severity)) {

Check warning on line 132 in src/ErrorHandler.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "BitwiseAnd": --- Original +++ New @@ @@ if (!$this->enabled) { return false; } - if (!(error_reporting() & $severity)) { + if (!(error_reporting() | $severity)) { // This error code is not included in error_reporting. return true; }
// This error code is not included in error_reporting.
return true;
}

$backtrace = debug_backtrace(0);

Check warning on line 137 in src/ErrorHandler.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "IncrementInteger": --- Original +++ New @@ @@ // This error code is not included in error_reporting. return true; } - $backtrace = debug_backtrace(0); + $backtrace = debug_backtrace(1); array_shift($backtrace); throw new ErrorException($message, $severity, $severity, $file, $line, null, $backtrace); });

Check warning on line 137 in src/ErrorHandler.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "DecrementInteger": --- Original +++ New @@ @@ // This error code is not included in error_reporting. return true; } - $backtrace = debug_backtrace(0); + $backtrace = debug_backtrace(-1); array_shift($backtrace); throw new ErrorException($message, $severity, $severity, $file, $line, null, $backtrace); });
array_shift($backtrace);
throw new ErrorException($message, $severity, $severity, $file, $line, null, $backtrace);
});
Expand Down
2 changes: 1 addition & 1 deletion src/Exception/ErrorException.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*
* @final
*/
class ErrorException extends \ErrorException implements FriendlyExceptionInterface
final class ErrorException extends \ErrorException implements FriendlyExceptionInterface
{
/** @psalm-suppress MissingClassConstType Private constants never change. */
private const ERROR_NAMES = [
Expand Down
2 changes: 1 addition & 1 deletion src/Exception/UserException.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
* @final
*/
#[Attribute(Attribute::TARGET_CLASS)]
class UserException extends Exception
final class UserException extends Exception
{
public static function isUserException(Throwable $throwable): bool
{
Expand Down
190 changes: 0 additions & 190 deletions src/Factory/ThrowableResponseFactory.php

This file was deleted.

8 changes: 4 additions & 4 deletions src/Middleware/ErrorCatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@
use Psr\Http\Server\RequestHandlerInterface;
use Yiisoft\ErrorHandler\CompositeException;
use Yiisoft\ErrorHandler\Event\ApplicationError;
use Yiisoft\ErrorHandler\ThrowableResponseFactoryInterface;
use Yiisoft\ErrorHandler\ThrowableResponseActionInterface;

/**
* `ErrorCatcher` catches all throwables from the next middlewares
* and renders it with a handler that implements the `ThrowableResponseFactoryInterface`.
* and renders it with a handler that implements the `ThrowableResponseActionInterface`.
*/
final class ErrorCatcher implements MiddlewareInterface
{
public function __construct(
private readonly ThrowableResponseFactoryInterface $throwableResponseFactory,
private readonly ThrowableResponseActionInterface $throwableResponseAction,
private readonly ?EventDispatcherInterface $eventDispatcher = null,
) {
}
Expand All @@ -37,7 +37,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
$t = new CompositeException($e, $t);
}

return $this->throwableResponseFactory->create($t, $request);
return $this->throwableResponseAction->handle($request, $t);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,19 @@
use Yiisoft\Http\Status;

/**
* `ThrowableResponseFactory` produces a response with rendered `Throwable` object.
* `ThrowableResponseAction` produces a response with rendered `Throwable` object.
*/
final class ThrowableResponseFactory implements ThrowableResponseFactoryInterface
final class ThrowableResponseAction implements ThrowableResponseActionInterface
{
private readonly HeadersProvider $headersProvider;

public function __construct(
private readonly ResponseFactoryInterface $responseFactory,
private readonly ErrorHandler $errorHandler,
private readonly RendererProviderInterface $rendererProvider,
?HeadersProvider $headersProvider = null,
private readonly HeadersProvider $headersProvider = new HeadersProvider(),
) {
$this->headersProvider = $headersProvider ?? new HeadersProvider();
}

public function create(Throwable $throwable, ServerRequestInterface $request): ResponseInterface
public function handle(ServerRequestInterface $request, Throwable $throwable): ResponseInterface
{
$renderer = $this->rendererProvider->get($request);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
use Psr\Http\Message\ServerRequestInterface;

/**
* `ThrowableResponseFactoryInterface` produces a response for `Throwable` object.
* `ThrowableResponseActionInterface` produces a response for `Throwable` object.
*/
interface ThrowableResponseFactoryInterface
interface ThrowableResponseActionInterface
{
/**
* Handles a `Throwable` object and produces a response.
*/
public function create(Throwable $throwable, ServerRequestInterface $request): ResponseInterface;
public function handle(ServerRequestInterface $request, Throwable $throwable): ResponseInterface;
}
5 changes: 1 addition & 4 deletions tests/ErrorHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

use PHPUnit\Framework\Attributes\WithoutErrorHandler;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Throwable;
use Yiisoft\ErrorHandler\ErrorHandler;
Expand All @@ -16,14 +15,12 @@
final class ErrorHandlerTest extends TestCase
{
private ErrorHandler $errorHandler;
private LoggerInterface $loggerMock;
private ThrowableRendererInterface $throwableRendererMock;

protected function setUp(): void
{
$this->loggerMock = $this->createMock(LoggerInterface::class);
$this->throwableRendererMock = $this->createMock(ThrowableRendererInterface::class);
$this->errorHandler = new ErrorHandler($this->loggerMock, $this->throwableRendererMock);
$this->errorHandler = new ErrorHandler($this->throwableRendererMock);
$this->errorHandler->memoryReserveSize(0);
}

Expand Down
Loading
Loading