make($callback[0]); } if (!is_callable($callback)) { throw new InvalidArgumentException('Callback is not callable.'); } return call_user_func_array($callback, self::getMethodDependencies($container, $callback, $parameters)); } /** * Get all dependencies for a given method. * * @param callable|string $callback * @throws ReflectionException */ protected static function getMethodDependencies(ContainerInterface $container, $callback, array $parameters = []): array { $dependencies = []; foreach (ReflectionUtil::getCallReflector($callback)->getParameters() as $i => $parameter) { if (isset($parameters[$i]) && $parameter->hasType() && ($type = $parameter->getType())) { if ($type instanceof \ReflectionNamedType && gettype($parameters[$i]) === $type->getName()) { $dependencies[] = $parameters[$i]; continue; } } static::addDependencyForCallParameter($container, $parameter, $parameters, $dependencies); } return array_merge($dependencies, array_values($parameters)); } /** * Get the dependency for the given call parameter. * * @throws EntryResolutionException */ protected static function addDependencyForCallParameter( ContainerInterface $container, ReflectionParameter $parameter, array &$parameters, array &$dependencies ): void { if (array_key_exists($param_name = $parameter->getName(), $parameters)) { $dependencies[] = $parameters[$param_name]; unset($parameters[$param_name]); } elseif (!is_null($class_name = ReflectionUtil::getParameterClassName($parameter))) { if (array_key_exists($class_name, $parameters)) { $dependencies[] = $parameters[$class_name]; unset($parameters[$class_name]); } elseif ($parameter->isVariadic()) { $variadic_dependencies = $container->make($class_name); $dependencies = array_merge($dependencies, is_array($variadic_dependencies) ? $variadic_dependencies : [$variadic_dependencies]); } else { $dependencies[] = $container->make($class_name); } } elseif ($parameter->isDefaultValueAvailable()) { $dependencies[] = $parameter->getDefaultValue(); } elseif (!array_key_exists($param_name, $parameters) && !$parameter->isOptional()) { $message = "无法解析类 {$parameter->getDeclaringClass()->getName()} 的依赖 {$parameter}"; throw new EntryResolutionException($message); } } }