Skip to content

Commit

Permalink
Improve ErrorLevel class
Browse files Browse the repository at this point in the history
  • Loading branch information
nyamsprod committed Nov 26, 2023
1 parent ed65ef7 commit c031516
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 128 deletions.
45 changes: 16 additions & 29 deletions src/Error/Cloak.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,6 @@
use function restore_error_handler;
use function set_error_handler;

use const E_ALL;
use const E_DEPRECATED;
use const E_NOTICE;
use const E_STRICT;
use const E_USER_DEPRECATED;
use const E_USER_NOTICE;
use const E_USER_WARNING;
use const E_WARNING;

class Cloak
{
public const FOLLOW_ENV = 0;
Expand All @@ -33,14 +24,15 @@ class Cloak
public function __construct(
protected readonly Closure $closure,
protected readonly int $onError = self::FOLLOW_ENV,
ErrorLevel|int|null $errorLevel = null
ErrorLevel|string|int|null $errorLevel = null
) {
$errorLevel = $errorLevel ?? ErrorLevel::fromEnvironment();
if (!$errorLevel instanceof ErrorLevel) {
$errorLevel = ErrorLevel::new($errorLevel);
}
$this->errorLevel = match (true) {
$errorLevel instanceof ErrorLevel => $errorLevel,
is_string($errorLevel) => ErrorLevel::fromName($errorLevel),
is_int($errorLevel) => ErrorLevel::fromValue($errorLevel),
default => ErrorLevel::fromEnvironment(),
};

$this->errorLevel = $errorLevel;
$this->errors = new CloakedErrors();
}

Expand All @@ -56,47 +48,42 @@ public static function silentOnError(): void

public static function fromEnvironment(Closure $closure, int $onError = self::FOLLOW_ENV): self
{
return new self(closure: $closure, onError: $onError, errorLevel: $onError);
return new self($closure, $onError);
}

public static function warning(Closure $closure, int $onError = self::FOLLOW_ENV): self
{
return new self($closure, $onError, E_WARNING);
return new self($closure, $onError, 'E_WARNING');
}

public static function notice(Closure $closure, int $onError = self::FOLLOW_ENV): self
{
return new self($closure, $onError, E_NOTICE);
return new self($closure, $onError, 'E_NOTICE');
}

public static function deprecated(Closure $closure, int $onError = self::FOLLOW_ENV): self
{
return new self($closure, $onError, E_DEPRECATED);
}

public static function strict(Closure $closure, int $onError = self::FOLLOW_ENV): self
{
return new self($closure, $onError, E_STRICT);
return new self($closure, $onError, 'E_DEPRECATED');
}

public static function userWarning(Closure $closure, int $onError = self::FOLLOW_ENV): self
{
return new self($closure, $onError, E_USER_WARNING);
return new self($closure, $onError, 'E_USER_WARNING');
}

public static function userNotice(Closure $closure, int $onError = self::FOLLOW_ENV): self
{
return new self($closure, $onError, E_USER_NOTICE);
return new self($closure, $onError, 'E_USER_NOTICE');
}

public static function userDeprecated(Closure $closure, int $onError = self::FOLLOW_ENV): self
{
return new self($closure, $onError, E_USER_DEPRECATED);
return new self($closure, $onError, 'E_USER_DEPRECATED');
}

public static function all(Closure $closure, int $onError = self::FOLLOW_ENV): self
{
return new self($closure, $onError, E_ALL);
return new self($closure, $onError, 'E_ALL');
}

/**
Expand All @@ -119,7 +106,7 @@ public function __invoke(mixed ...$arguments): mixed
};

try {
set_error_handler($errorHandler, $this->errorLevel->toBytes());
set_error_handler($errorHandler, $this->errorLevel->value());
$result = ($this->closure)(...$arguments);
} finally {
restore_error_handler();
Expand Down
2 changes: 1 addition & 1 deletion src/Error/CloakTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public function testSpecificBehaviourOverrideGeneralErrorSetting(): void
public function testCaptureNothingThrowNoException(): void
{
Cloak::throwOnError();
$strtoupper = Cloak::strict(strtoupper(...));
$strtoupper = Cloak::notice(strtoupper(...));

self::assertSame('FOO', $strtoupper('foo'));
}
Expand Down
142 changes: 56 additions & 86 deletions src/Error/ErrorLevel.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@

namespace Bakame\Aide\Error;

use OutOfRangeException;
use ValueError;

use function array_filter;
use function array_map;
use function array_key_exists;
use function array_search;
use function error_reporting;
use function in_array;

use const E_ALL;
use const E_COMPILE_ERROR;
Expand All @@ -31,24 +29,22 @@
class ErrorLevel
{
protected const LEVELS = [
-1,
0,
E_ERROR,
E_WARNING,
E_PARSE,
E_NOTICE,
E_CORE_ERROR,
E_CORE_WARNING,
E_COMPILE_ERROR,
E_COMPILE_WARNING,
E_RECOVERABLE_ERROR,
E_ALL,
E_DEPRECATED,
E_STRICT,
E_USER_ERROR,
E_USER_WARNING,
E_USER_NOTICE,
E_USER_DEPRECATED,
E_ALL => 'E_ALL',
E_ERROR => 'E_ERROR',
E_WARNING => 'E_WARNING',
E_PARSE => 'E_PARSE',
E_NOTICE => 'E_NOTICE',
E_CORE_ERROR => 'E_CORE_ERROR',
E_CORE_WARNING => 'E_CORE_WARNING',
E_COMPILE_ERROR => 'E_COMPILE_ERROR',
E_COMPILE_WARNING => 'E_COMPILE_WARNING',
E_USER_ERROR => 'E_USER_ERROR',
E_USER_WARNING => 'E_USER_WARNING',
E_USER_NOTICE => 'E_USER_NOTICE',
E_STRICT => 'E_STRICT',
E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR',
E_DEPRECATED => 'E_DEPRECATED',
E_USER_DEPRECATED => 'E_USER_DEPRECATED',
];

private function __construct(protected readonly int $value)
Expand All @@ -58,99 +54,73 @@ private function __construct(protected readonly int $value)
}
}

public static function new(int $bytes = 0): self
public static function fromValue(int $value): self
{
return new self($bytes);
return new self($value);
}

public static function fromEnvironment(): self
public static function fromName(string $name): self
{
$errorReporting = error_reporting(-1);
error_reporting($errorReporting);
/** @var int|false $errorLevel */
$errorLevel = array_search($name, self::LEVELS, true);
if (false === $errorLevel) {
throw new ValueError('The name `'.$name.'` is invalid or unknown error reporting level name.');
}

return new self($errorReporting);
return new self($errorLevel);
}

public function toBytes(): int
public static function fromEnvironment(): self
{
return $this->value;
return new self(error_reporting());
}

public function contains(self|int ...$levels): bool
public static function fromExclusion(string|int ...$levels): self
{
if (-1 === $this->value) {
return true;
}

if (0 === $this->value) {
return false;
}

foreach ($levels as $level) {
$level = $level instanceof self ? $level->value : $level;
if (0 !== ($level & $this->value)) {
return true;
return new self(array_reduce($levels, function (int $carry, string|int $level) {
$errorLevel = is_string($level) ? self::fromName($level)->value : $level;
if (!array_key_exists($errorLevel, self::LEVELS)) {
throw new ValueError('The value `'.$level.'` is invalid as a error reporting level value in PHP.');
}
}

return false;
return $carry & ~$errorLevel;
}, E_ALL));
}

public function include(self|int ...$levels): self
public static function fromInclusion(string|int ...$levels): self
{
$levels = array_map(fn (self|int $level) => match (true) {
$level instanceof self => $level->value,
default => $level,
}, $levels);

if ([] === $levels) {
return $this;
}

if (in_array(-1, $levels, true)) {
return self::new(-1);
}

if (in_array(0, $levels, true)) {
return self::new(0);
}

$value = 0 === $this->value ? $levels[0] : $this->value;
foreach ($levels as $level) {
if (!in_array($level, self::LEVELS, true)) {
throw new OutOfRangeException('The error reporting level value `'.$level.'` is invalid.');
return new self(array_reduce($levels, function (int $carry, string|int $level) {
$errorLevel = is_string($level) ? self::fromName($level)->value : $level;
if (!array_key_exists($errorLevel, self::LEVELS)) {
throw new ValueError('The value `'.$level.'` is invalid as a error reporting level value in PHP.');
}

$value &= $level;
}

return self::new($value);
return $carry | $errorLevel;
}, 0));
}

public function ignore(self|int ...$levels): self
public function value(): int
{
$levels = array_map(fn (self|int $level) => match (true) {
$level instanceof self => $level->value,
default => $level,
}, $levels);
return $this->value;
}

if (in_array(-1, $levels, true)) {
return self::new(0);
public function contains(self|int ...$levels): bool
{
if ([] === $levels || 0 === $this->value) {
return false;
}

$levels = array_filter($levels, fn (int $level) => 0 !== $level && $this->value !== $level);
if ([] === $levels) {
return $this;
if (-1 === $this->value) {
return true;
}

$value = $this->value;
foreach ($levels as $level) {
if (!in_array($level, self::LEVELS, true)) {
throw new OutOfRangeException('The error reporting level value `'.$level.'` is invalid.');
$level = $level instanceof self ? $level->value : $level;
if (1 > $level || $level !== ($this->value & $level)) {
return false;
}
$value &= ~$level;
}

return self::new($value);
return true;
}
}
Loading

0 comments on commit c031516

Please sign in to comment.