From f5d34198e7e9655272b72c1b08e21b39d4104ec7 Mon Sep 17 00:00:00 2001 From: sunxyw Date: Thu, 7 Apr 2022 19:09:02 +0800 Subject: [PATCH] add container call method --- src/ZM/Container/BoundMethod.php | 137 ++++++++++++++++++++++++ src/ZM/Container/ContainerInterface.php | 7 +- src/ZM/Container/WorkerContainer.php | 30 ++---- 3 files changed, 148 insertions(+), 26 deletions(-) create mode 100644 src/ZM/Container/BoundMethod.php diff --git a/src/ZM/Container/BoundMethod.php b/src/ZM/Container/BoundMethod.php new file mode 100644 index 00000000..e2a6ae40 --- /dev/null +++ b/src/ZM/Container/BoundMethod.php @@ -0,0 +1,137 @@ +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)); + } + + /** + * 判断调用的是否为非静态方法 + * + * @param array|string $callback + * @throws ReflectionException + */ + protected static function isCallingNonStaticMethod($callback): bool + { + if (is_array($callback) && is_string($callback[0])) { + $reflection = new ReflectionMethod($callback[0], $callback[1]); + return !$reflection->isStatic(); + } + return false; + } + + /** + * 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 (static::getCallReflector($callback)->getParameters() as $parameter) { + static::addDependencyForCallParameter($container, $parameter, $parameters, $dependencies); + } + + return array_merge($dependencies, array_values($parameters)); + } + + /** + * Get the proper reflection instance for the given callback. + * + * @param callable|string $callback + * @throws \ReflectionException + * @return ReflectionFunctionAbstract + */ + protected static function getCallReflector($callback) + { + if (is_string($callback) && str_contains($callback, '::')) { + $callback = explode('::', $callback); + } elseif (is_object($callback) && !$callback instanceof Closure) { + $callback = [$callback, '__invoke']; + } + + return is_array($callback) + ? new ReflectionMethod($callback[0], $callback[1]) + : new ReflectionFunction($callback); + } + + /** + * 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); + } + } +} diff --git a/src/ZM/Container/ContainerInterface.php b/src/ZM/Container/ContainerInterface.php index e667a547..26616c66 100644 --- a/src/ZM/Container/ContainerInterface.php +++ b/src/ZM/Container/ContainerInterface.php @@ -101,9 +101,10 @@ interface ContainerInterface extends PsrContainerInterface /** * 调用对应的方法,并自动注入依赖 * - * @param callable $callback 对应的方法 - * @param array $parameters 参数 + * @param callable $callback 对应的方法 + * @param array $parameters 参数 + * @param null|string $default_method 默认方法 * @return mixed */ - public function call(callable $callback, array $parameters = []); + public function call(callable $callback, array $parameters = [], string $default_method = null); } diff --git a/src/ZM/Container/WorkerContainer.php b/src/ZM/Container/WorkerContainer.php index 41d0c634..8f54b999 100644 --- a/src/ZM/Container/WorkerContainer.php +++ b/src/ZM/Container/WorkerContainer.php @@ -13,6 +13,7 @@ use ReflectionClass; use ReflectionException; use ReflectionNamedType; use ReflectionParameter; +use ZM\Utils\ReflectionUtil; use ZM\Utils\SingletonTrait; class WorkerContainer implements ContainerInterface @@ -310,13 +311,14 @@ class WorkerContainer implements ContainerInterface /** * 调用对应的方法,并自动注入依赖 * - * @param callable $callback 对应的方法 - * @param array $parameters 参数 + * @param callable|string $callback 对应的方法 + * @param array $parameters 参数 + * @param null|string $default_method 默认方法 * @return mixed */ - public function call(callable $callback, array $parameters = []) + public function call($callback, array $parameters = [], string $default_method = null) { - // TODO: Implement call() method. + return BoundMethod::call($this, $callback, $parameters, $default_method); } /** @@ -474,26 +476,8 @@ class WorkerContainer implements ContainerInterface continue; } - // 获取参数类型 - $type = $dependency->getType(); - // 没有声明类型或为基本类型 - if (!$type instanceof ReflectionNamedType || $type->isBuiltin()) { - $class_name = null; - } else { - // 获取类名 - $class_name = $type->getName(); - // 如果存在父类 - if (!is_null($class = $dependency->getDeclaringClass())) { - if ($class_name === 'self') { - $class_name = $class->getName(); - } elseif ($class_name === 'parent') { - $class_name = $class->getParentClass()->getName(); - } - } - } - // 如果类名为空,则代表此依赖是基本类型,且无法对其进行依赖解析 - $results[] = is_null($class_name) + $results[] = is_null(ReflectionUtil::getParameterClassName($dependency)) ? $this->resolvePrimitive($dependency) : $this->resolveClass($dependency); }