PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.5.0
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.5.0
4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.5.2 All 199 releases
betterdocs / includes / Dependencies / Invoker / CallableResolver.php

CallableResolver.php in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 4.5.0, at includes/Dependencies/Invoker/CallableResolver.php

125 lines 3.8 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 WPDeveloper\BetterDocs\Dependencies\Invoker;
4
5 use Closure;
6 use WPDeveloper\BetterDocs\Dependencies\Invoker\Exception\NotCallableException;
7 use WPDeveloper\BetterDocs\Dependencies\Psr\Container\ContainerInterface;
8 use WPDeveloper\BetterDocs\Dependencies\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