PluginProbe
The Innovative Form Builder – IvyForms / 0.3
The Innovative Form Builder – IvyForms v0.3
1.5.1 1.5 1.4.1 1.4 trunk 0.1.2 0.2 0.2.1 0.3 0.3.1 0.4 0.5 0.6 0.6.1 0.6.1-backup 0.6.1.1 0.7 0.8 0.8.1 0.8.2 0.9 0.9.1 1.0 1.1 1.1.1 All 27 releases
ivyforms / backend / vendor / php-di / invoker / src / CallableResolver.php

CallableResolver.php in The Innovative Form Builder – IvyForms 0.3, at backend/vendor/php-di/invoker/src/CallableResolver.php

125 lines 3.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php declare(strict_types=1);
2
3 namespace Invoker;
4
5 use Closure;
6 use Invoker\Exception\NotCallableException;
7 use Psr\Container\ContainerInterface;
8 use Psr\Container\NotFoundExceptionInterface;
9 use ReflectionException;
10 use ReflectionMethod;
11
12 /**
13 * Resolves a callable from a container.
14 */
15 class CallableResolver
16 {
17 /** @var ContainerInterface */
18 private $container;
19
20 public function __construct(ContainerInterface $container)
21 {
22 $this->container = $container;
23 }
24
25 /**
26 * Resolve the given callable into a real PHP callable.
27 *
28 * @param callable|string|array $callable
29 * @return callable Real PHP callable.
30 * @throws NotCallableException|ReflectionException
31 */
32 public function resolve($callable): callable
33 {
34 if (is_string($callable) && strpos($callable, '::') !== false) {
35 $callable = explode('::', $callable, 2);
36 }
37
38 $callable = $this->resolveFromContainer($callable);
39
40 if (! is_callable($callable)) {
41 throw NotCallableException::fromInvalidCallable($callable, true);
42 }
43
44 return $callable;
45 }
46
47 /**
48 * @param callable|string|array $callable
49 * @return callable|mixed
50 * @throws NotCallableException|ReflectionException
51 */
52 private function resolveFromContainer($callable)
53 {
54 // Shortcut for a very common use case
55 if ($callable instanceof Closure) {
56 return $callable;
57 }
58
59 // If it's already a callable there is nothing to do
60 if (is_callable($callable)) {
61 // TODO with PHP 8 that should not be necessary to check this anymore
62 if (! $this->isStaticCallToNonStaticMethod($callable)) {
63 return $callable;
64 }
65 }
66
67 // The callable is a container entry name
68 if (is_string($callable)) {
69 try {
70 return $this->container->get($callable);
71 } catch (NotFoundExceptionInterface $e) {
72 if ($this->container->has($callable)) {
73 throw $e;
74 }
75 throw NotCallableException::fromInvalidCallable($callable, true);
76 }
77 }
78
79 // The callable is an array whose first item is a container entry name
80 // e.g. ['some-container-entry', 'methodToCall']
81 if (is_array($callable) && is_string($callable[0])) {
82 try {
83 // Replace the container entry name by the actual object
84 $callable[0] = $this->container->get($callable[0]);
85 return $callable;
86 } catch (NotFoundExceptionInterface $e) {
87 if ($this->container->has($callable[0])) {
88 throw $e;
89 }
90 throw new NotCallableException(sprintf(
91 'Cannot call %s() on %s because it is not a class nor a valid container entry',
92 $callable[1],
93 $callable[0]
94 ));
95 }
96 }
97
98 // Unrecognized stuff, we let it fail later
99 return $callable;
100 }
101
102 /**
103 * Check if the callable represents a static call to a non-static method.
104 *
105 * @param mixed $callable
106 * @throws ReflectionException
107 */
108 private function isStaticCallToNonStaticMethod($callable): bool
109 {
110 if (is_array($callable) && is_string($callable[0])) {
111 [$class, $method] = $callable;
112
113 if (! method_exists($class, $method)) {
114 return false;
115 }
116
117 $reflection = new ReflectionMethod($class, $method);
118
119 return ! $reflection->isStatic();
120 }
121
122 return false;
123 }
124 }
125