bindings[$name] = $value; } public function get(string $name): mixed { return $this->bindings[$name] ?? null; } public function call(callable|array|string $handler, array $parameters = []): mixed { if (is_array($handler)) { return $this->callMethod($handler, $parameters); } if (is_callable($handler)) { return $this->callFunction($handler, $parameters); } throw new Exception('Invalid handler.'); } protected function callFunction(callable $handler, array $parameters): mixed { $reflection = new ReflectionFunction($handler); return $reflection->invokeArgs($this->resolveArgs($reflection, $parameters)); } protected function callMethod(array $handler, array $parameters): mixed { [$class, $method] = $handler; if (is_string($class)) { $class = new $class(); } $reflection = new ReflectionMethod($class, $method); return $reflection->invokeArgs($class, $this->resolveArgs($reflection, $parameters)); } protected function resolveArgs(\ReflectionFunctionAbstract $reflection, array $parameters): array { $args = []; foreach ($reflection->getParameters() as $param) { $name = $param->getName(); if (array_key_exists($name, $parameters)) { $args[] = $parameters[$name]; continue; } $type = $param->getType(); if ($type instanceof \ReflectionNamedType && !$type->isBuiltin()) { $typeName = $type->getName(); if (array_key_exists($typeName, $this->bindings)) { $args[] = $this->bindings[$typeName]; continue; } } $args[] = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null; } return $args; } }