The payload data */ private array $payload = []; public function __construct(string $commandName, array $payload) { $this->commandName = $commandName; $this->payload = $payload; } public function getCommandName(): string { return $this->commandName; } public function getPayload(): array { return $this->payload; } public function __get($name) { return $this->payload[$name] ?? null; } public function toMethodParameters(callable $callable): array { $refl = new ReflectionFunction($callable); $args = []; // Go over the arguments foreach ($refl->getParameters() as $parameter) { $name = $parameter->getName(); if (!$parameter->hasType()) { // use name $args[] = isset($this->payload[$name]) ? $this->payload[$name] : ($parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null); } else { // use name and type $type = $parameter->getType(); if ($type instanceof ReflectionNamedType && $type->isBuiltin()) { $typeName = $type->getName(); $arg = isset($this->payload[$name]) ? $this->payload[$name] : ($parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null); $args[] = match ($typeName) { 'string' => strval($arg), 'boolean' => boolval($arg), 'array' => (array)$arg, 'object' => (object)$arg, 'integer' => intval($arg), 'float' => floatval($arg), default => $arg, }; } elseif ($type instanceof ReflectionNamedType) { $typeName = $type->getName(); switch ($typeName) { case Context::class: $args[] = $this; break; default: $args[] = null; // FIXME how to handle this? } } elseif ($type instanceof ReflectionUnionType) { $args[] = null; // FIXME how to handle this? } elseif ($type instanceof ReflectionIntersectionType) { $args[] = null; // FIXME how to handle this? } } } return $args; } }