Viewing file: Callback.php (3.05 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php
declare(strict_types=1);
/** * This file is part of the Carbon package. * * (c) Brian Nesbitt <brian@nesbot.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */
namespace Carbon;
use Closure; use DateInterval; use DatePeriod; use DateTime; use DateTimeInterface; use DateTimeZone; use ReflectionFunction; use ReflectionNamedType; use ReflectionType;
final class Callback { private ?ReflectionFunction $function;
private function __construct(private readonly Closure $closure) { }
public static function fromClosure(Closure $closure): self { return new self($closure); }
public static function parameter(mixed $closure, mixed $value, string|int $index = 0): mixed { if ($closure instanceof Closure) { return self::fromClosure($closure)->prepareParameter($value, $index); }
return $value; }
public function getReflectionFunction(): ReflectionFunction { return $this->function ??= new ReflectionFunction($this->closure); }
public function prepareParameter(mixed $value, string|int $index = 0): mixed { $type = $this->getParameterType($index);
if (!($type instanceof ReflectionNamedType)) { return $value; }
$name = $type->getName();
if ($name === CarbonInterface::class) { $name = $value instanceof DateTime ? Carbon::class : CarbonImmutable::class; }
if (!class_exists($name) || is_a($value, $name)) { return $value; }
$class = $this->getPromotedClass($value);
if ($class && is_a($name, $class, true)) { return $name::instance($value); }
return $value; }
public function call(mixed ...$arguments): mixed { foreach ($arguments as $index => &$value) { if ($this->getPromotedClass($value)) { $value = $this->prepareParameter($value, $index); } }
return ($this->closure)(...$arguments); }
private function getParameterType(string|int $index): ?ReflectionType { $parameters = $this->getReflectionFunction()->getParameters();
if (\is_int($index)) { return ($parameters[$index] ?? null)?->getType(); }
foreach ($parameters as $parameter) { if ($parameter->getName() === $index) { return $parameter->getType(); } }
return null; }
/** @return class-string|null */ private function getPromotedClass(mixed $value): ?string { if ($value instanceof DateTimeInterface) { return CarbonInterface::class; }
if ($value instanceof DateInterval) { return CarbonInterval::class; }
if ($value instanceof DatePeriod) { return CarbonPeriod::class; }
if ($value instanceof DateTimeZone) { return CarbonTimeZone::class; }
return null; } }
|