Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Container;
4
 
5
use Closure;
6
use Illuminate\Contracts\Container\BindingResolutionException;
7
use InvalidArgumentException;
8
use ReflectionFunction;
9
use ReflectionMethod;
10
 
11
class BoundMethod
12
{
13
    /**
14
     * Call the given Closure / class@method and inject its dependencies.
15
     *
16
     * @param  \Illuminate\Container\Container  $container
17
     * @param  callable|string  $callback
18
     * @param  array  $parameters
19
     * @param  string|null  $defaultMethod
20
     * @return mixed
21
     *
22
     * @throws \ReflectionException
23
     * @throws \InvalidArgumentException
24
     */
25
    public static function call($container, $callback, array $parameters = [], $defaultMethod = null)
26
    {
27
        if (is_string($callback) && ! $defaultMethod && method_exists($callback, '__invoke')) {
28
            $defaultMethod = '__invoke';
29
        }
30
 
31
        if (static::isCallableWithAtSign($callback) || $defaultMethod) {
32
            return static::callClass($container, $callback, $parameters, $defaultMethod);
33
        }
34
 
35
        return static::callBoundMethod($container, $callback, function () use ($container, $callback, $parameters) {
36
            return $callback(...array_values(static::getMethodDependencies($container, $callback, $parameters)));
37
        });
38
    }
39
 
40
    /**
41
     * Call a string reference to a class using Class@method syntax.
42
     *
43
     * @param  \Illuminate\Container\Container  $container
44
     * @param  string  $target
45
     * @param  array  $parameters
46
     * @param  string|null  $defaultMethod
47
     * @return mixed
48
     *
49
     * @throws \InvalidArgumentException
50
     */
51
    protected static function callClass($container, $target, array $parameters = [], $defaultMethod = null)
52
    {
53
        $segments = explode('@', $target);
54
 
55
        // We will assume an @ sign is used to delimit the class name from the method
56
        // name. We will split on this @ sign and then build a callable array that
57
        // we can pass right back into the "call" method for dependency binding.
58
        $method = count($segments) === 2
59
                        ? $segments[1] : $defaultMethod;
60
 
61
        if (is_null($method)) {
62
            throw new InvalidArgumentException('Method not provided.');
63
        }
64
 
65
        return static::call(
66
            $container, [$container->make($segments[0]), $method], $parameters
67
        );
68
    }
69
 
70
    /**
71
     * Call a method that has been bound to the container.
72
     *
73
     * @param  \Illuminate\Container\Container  $container
74
     * @param  callable  $callback
75
     * @param  mixed  $default
76
     * @return mixed
77
     */
78
    protected static function callBoundMethod($container, $callback, $default)
79
    {
80
        if (! is_array($callback)) {
81
            return Util::unwrapIfClosure($default);
82
        }
83
 
84
        // Here we need to turn the array callable into a Class@method string we can use to
85
        // examine the container and see if there are any method bindings for this given
86
        // method. If there are, we can call this method binding callback immediately.
87
        $method = static::normalizeMethod($callback);
88
 
89
        if ($container->hasMethodBinding($method)) {
90
            return $container->callMethodBinding($method, $callback[0]);
91
        }
92
 
93
        return Util::unwrapIfClosure($default);
94
    }
95
 
96
    /**
97
     * Normalize the given callback into a Class@method string.
98
     *
99
     * @param  callable  $callback
100
     * @return string
101
     */
102
    protected static function normalizeMethod($callback)
103
    {
104
        $class = is_string($callback[0]) ? $callback[0] : get_class($callback[0]);
105
 
106
        return "{$class}@{$callback[1]}";
107
    }
108
 
109
    /**
110
     * Get all dependencies for a given method.
111
     *
112
     * @param  \Illuminate\Container\Container  $container
113
     * @param  callable|string  $callback
114
     * @param  array  $parameters
115
     * @return array
116
     *
117
     * @throws \ReflectionException
118
     */
119
    protected static function getMethodDependencies($container, $callback, array $parameters = [])
120
    {
121
        $dependencies = [];
122
 
123
        foreach (static::getCallReflector($callback)->getParameters() as $parameter) {
124
            static::addDependencyForCallParameter($container, $parameter, $parameters, $dependencies);
125
        }
126
 
127
        return array_merge($dependencies, array_values($parameters));
128
    }
129
 
130
    /**
131
     * Get the proper reflection instance for the given callback.
132
     *
133
     * @param  callable|string  $callback
134
     * @return \ReflectionFunctionAbstract
135
     *
136
     * @throws \ReflectionException
137
     */
138
    protected static function getCallReflector($callback)
139
    {
140
        if (is_string($callback) && str_contains($callback, '::')) {
141
            $callback = explode('::', $callback);
142
        } elseif (is_object($callback) && ! $callback instanceof Closure) {
143
            $callback = [$callback, '__invoke'];
144
        }
145
 
146
        return is_array($callback)
147
                        ? new ReflectionMethod($callback[0], $callback[1])
148
                        : new ReflectionFunction($callback);
149
    }
150
 
151
    /**
152
     * Get the dependency for the given call parameter.
153
     *
154
     * @param  \Illuminate\Container\Container  $container
155
     * @param  \ReflectionParameter  $parameter
156
     * @param  array  $parameters
157
     * @param  array  $dependencies
158
     * @return void
159
     *
160
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
161
     */
162
    protected static function addDependencyForCallParameter($container, $parameter,
163
                                                            array &$parameters, &$dependencies)
164
    {
165
        if (array_key_exists($paramName = $parameter->getName(), $parameters)) {
166
            $dependencies[] = $parameters[$paramName];
167
 
168
            unset($parameters[$paramName]);
169
        } elseif (! is_null($className = Util::getParameterClassName($parameter))) {
170
            if (array_key_exists($className, $parameters)) {
171
                $dependencies[] = $parameters[$className];
172
 
173
                unset($parameters[$className]);
174
            } elseif ($parameter->isVariadic()) {
175
                $variadicDependencies = $container->make($className);
176
 
177
                $dependencies = array_merge($dependencies, is_array($variadicDependencies)
178
                            ? $variadicDependencies
179
                            : [$variadicDependencies]);
180
            } else {
181
                $dependencies[] = $container->make($className);
182
            }
183
        } elseif ($parameter->isDefaultValueAvailable()) {
184
            $dependencies[] = $parameter->getDefaultValue();
185
        } elseif (! $parameter->isOptional() && ! array_key_exists($paramName, $parameters)) {
186
            $message = "Unable to resolve dependency [{$parameter}] in class {$parameter->getDeclaringClass()->getName()}";
187
 
188
            throw new BindingResolutionException($message);
189
        }
190
    }
191
 
192
    /**
193
     * Determine if the given string is in Class@method syntax.
194
     *
195
     * @param  mixed  $callback
196
     * @return bool
197
     */
198
    protected static function isCallableWithAtSign($callback)
199
    {
200
        return is_string($callback) && str_contains($callback, '@');
201
    }
202
}