add FilteredCallable to replace Dispatcher events to named callables (self explanatory).

- FilteredCallable wraps a callable and helps static analyzers to check if after filters are using the callable return type as output type.
- FilteredCallable handles after filters with two parameters (deprecated) and one parameter (new required signature)
dispatcher-rework
fadrian06 3 days ago
parent bb6932e92e
commit 2682e3298f

@ -0,0 +1,90 @@
<?php
declare(strict_types=1);
namespace flight\core;
use Closure;
use ReflectionFunction;
use Throwable;
/**
* @template CallableWithoutFilters of Closure
* @template Output of mixed
*/
final class FilteredCallable
{
/**
* @readonly
* @var CallableWithoutFilters
*/
private $closure;
/** @var (callable(mixed[] &$input): (void|never|false))[] */
private array $beforeFilters = [];
/** @var (callable(mixed &$output): (void|never|false))[] */
private array $afterFilters = [];
/** @param CallableWithoutFilters|callable(): Output $callable */
public function __construct(callable $callable)
{
$this->closure = Closure::fromCallable($callable);
}
/**
* @param mixed ...$input
* @return Output
* @throws Throwable
*/
public function __invoke(...$input)
{
foreach ($this->beforeFilters as $filter) {
$filterReturnValue = $filter($input);
if ($filterReturnValue === false) {
break;
}
}
$closure = $this->closure;
$output = $closure(...$input);
foreach ($this->afterFilters as $filter) {
$filterReturnValue = $filter($output);
if ($filterReturnValue === false) {
break;
}
}
return $output;
}
/** @param callable(mixed[] &$input): (void|never|false) $filter */
public function pushBeforeFilter(callable $filter): void
{
if (!in_array($filter, $this->beforeFilters)) {
$this->beforeFilters[] = $filter;
}
}
/** @param callable(Output &$output): (void|never|false) $filter */
public function pushAfterFilter(callable $filter): void
{
if (!in_array($filter, $this->afterFilters)) {
$filterReflectionFunction = new ReflectionFunction($filter);
if ($filterReflectionFunction->getNumberOfParameters() === 2) {
$filter = static function (&$output) use ($filter) {
static $input = [];
return $filter($input, $output);
};
}
$this->afterFilters[] = $filter;
}
}
}
Loading…
Cancel
Save