Viewing file: BoundMethod.php (6.94 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php
namespace Illuminate\Container;
use Closure; use Illuminate\Contracts\Container\BindingResolutionException; use InvalidArgumentException; use ReflectionFunction; use ReflectionMethod;
class BoundMethod { /** * Call the given Closure / class@method and inject its dependencies. * * @param \Illuminate\Container\Container $container * @param callable|string $callback * @param array $parameters * @param string|null $defaultMethod * @return mixed * * @throws \ReflectionException * @throws \InvalidArgumentException */ public static function call($container, $callback, array $parameters = [], $defaultMethod = null) { if (is_string($callback) && ! $defaultMethod && method_exists($callback, '__invoke')) { $defaultMethod = '__invoke'; }
if (static::isCallableWithAtSign($callback) || $defaultMethod) { return static::callClass($container, $callback, $parameters, $defaultMethod); }
return static::callBoundMethod($container, $callback, function () use ($container, $callback, $parameters) { return $callback(...array_values(static::getMethodDependencies($container, $callback, $parameters))); }); }
/** * Call a string reference to a class using Class@method syntax. * * @param \Illuminate\Container\Container $container * @param string $target * @param array $parameters * @param string|null $defaultMethod * @return mixed * * @throws \InvalidArgumentException */ protected static function callClass($container, $target, array $parameters = [], $defaultMethod = null) { $segments = explode('@', $target);
// We will assume an @ sign is used to delimit the class name from the method // name. We will split on this @ sign and then build a callable array that // we can pass right back into the "call" method for dependency binding. $method = count($segments) === 2 ? $segments[1] : $defaultMethod;
if (is_null($method)) { throw new InvalidArgumentException('Method not provided.'); }
return static::call( $container, [$container->make($segments[0]), $method], $parameters ); }
/** * Call a method that has been bound to the container. * * @param \Illuminate\Container\Container $container * @param callable $callback * @param mixed $default * @return mixed */ protected static function callBoundMethod($container, $callback, $default) { if (! is_array($callback)) { return Util::unwrapIfClosure($default); }
// Here we need to turn the array callable into a Class@method string we can use to // examine the container and see if there are any method bindings for this given // method. If there are, we can call this method binding callback immediately. $method = static::normalizeMethod($callback);
if ($container->hasMethodBinding($method)) { return $container->callMethodBinding($method, $callback[0]); }
return Util::unwrapIfClosure($default); }
/** * Normalize the given callback into a Class@method string. * * @param callable $callback * @return string */ protected static function normalizeMethod($callback) { $class = is_string($callback[0]) ? $callback[0] : get_class($callback[0]);
return "{$class}@{$callback[1]}"; }
/** * Get all dependencies for a given method. * * @param \Illuminate\Container\Container $container * @param callable|string $callback * @param array $parameters * @return array * * @throws \ReflectionException */ protected static function getMethodDependencies($container, $callback, array $parameters = []) { $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 * @return \ReflectionFunctionAbstract * * @throws \ReflectionException */ 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. * * @param \Illuminate\Container\Container $container * @param \ReflectionParameter $parameter * @param array $parameters * @param array $dependencies * @return void * * @throws \Illuminate\Contracts\Container\BindingResolutionException */ protected static function addDependencyForCallParameter($container, $parameter, array &$parameters, &$dependencies) { if (array_key_exists($paramName = $parameter->getName(), $parameters)) { $dependencies[] = $parameters[$paramName];
unset($parameters[$paramName]); } elseif (! is_null($className = Util::getParameterClassName($parameter))) { if (array_key_exists($className, $parameters)) { $dependencies[] = $parameters[$className];
unset($parameters[$className]); } elseif ($parameter->isVariadic()) { $variadicDependencies = $container->make($className);
$dependencies = array_merge($dependencies, is_array($variadicDependencies) ? $variadicDependencies : [$variadicDependencies]); } else { $dependencies[] = $container->make($className); } } elseif ($parameter->isDefaultValueAvailable()) { $dependencies[] = $parameter->getDefaultValue(); } elseif (! $parameter->isOptional() && ! array_key_exists($paramName, $parameters)) { $message = "Unable to resolve dependency [{$parameter}] in class {$parameter->getDeclaringClass()->getName()}";
throw new BindingResolutionException($message); } }
/** * Determine if the given string is in Class@method syntax. * * @param mixed $callback * @return bool */ protected static function isCallableWithAtSign($callback) { return is_string($callback) && str_contains($callback, '@'); } }
|