Mercurial > hg > isophonics-drupal-site
comparison vendor/psy/psysh/src/Psy/Command/ReflectingCommand.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 7a779792577d |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 /* | |
4 * This file is part of Psy Shell. | |
5 * | |
6 * (c) 2012-2017 Justin Hileman | |
7 * | |
8 * For the full copyright and license information, please view the LICENSE | |
9 * file that was distributed with this source code. | |
10 */ | |
11 | |
12 namespace Psy\Command; | |
13 | |
14 use Psy\Context; | |
15 use Psy\ContextAware; | |
16 use Psy\Exception\RuntimeException; | |
17 use Psy\Util\Mirror; | |
18 | |
19 /** | |
20 * An abstract command with helpers for inspecting the current context. | |
21 */ | |
22 abstract class ReflectingCommand extends Command implements ContextAware | |
23 { | |
24 const CLASS_OR_FUNC = '/^[\\\\\w]+$/'; | |
25 const INSTANCE = '/^\$(\w+)$/'; | |
26 const CLASS_MEMBER = '/^([\\\\\w]+)::(\w+)$/'; | |
27 const CLASS_STATIC = '/^([\\\\\w]+)::\$(\w+)$/'; | |
28 const INSTANCE_MEMBER = '/^\$(\w+)(::|->)(\w+)$/'; | |
29 const INSTANCE_STATIC = '/^\$(\w+)::\$(\w+)$/'; | |
30 const SUPERGLOBAL = '/^\$(GLOBALS|_(?:SERVER|ENV|FILES|COOKIE|POST|GET|SESSION))$/'; | |
31 | |
32 /** | |
33 * Context instance (for ContextAware interface). | |
34 * | |
35 * @var Context | |
36 */ | |
37 protected $context; | |
38 | |
39 /** | |
40 * ContextAware interface. | |
41 * | |
42 * @param Context $context | |
43 */ | |
44 public function setContext(Context $context) | |
45 { | |
46 $this->context = $context; | |
47 } | |
48 | |
49 /** | |
50 * Get the target for a value. | |
51 * | |
52 * @throws \InvalidArgumentException when the value specified can't be resolved | |
53 * | |
54 * @param string $valueName Function, class, variable, constant, method or property name | |
55 * @param bool $classOnly True if the name should only refer to a class, function or instance | |
56 * | |
57 * @return array (class or instance name, member name, kind) | |
58 */ | |
59 protected function getTarget($valueName, $classOnly = false) | |
60 { | |
61 $valueName = trim($valueName); | |
62 $matches = array(); | |
63 switch (true) { | |
64 case preg_match(self::SUPERGLOBAL, $valueName, $matches): | |
65 // @todo maybe do something interesting with these at some point? | |
66 if (array_key_exists($matches[1], $GLOBALS)) { | |
67 throw new RuntimeException('Unable to inspect a non-object'); | |
68 } else { | |
69 throw new RuntimeException('Unknown target: ' . $valueName); | |
70 } | |
71 | |
72 case preg_match(self::CLASS_OR_FUNC, $valueName, $matches): | |
73 return array($this->resolveName($matches[0], true), null, 0); | |
74 | |
75 case preg_match(self::INSTANCE, $valueName, $matches): | |
76 return array($this->resolveInstance($matches[1]), null, 0); | |
77 | |
78 case !$classOnly && preg_match(self::CLASS_MEMBER, $valueName, $matches): | |
79 return array($this->resolveName($matches[1]), $matches[2], Mirror::CONSTANT | Mirror::METHOD); | |
80 | |
81 case !$classOnly && preg_match(self::CLASS_STATIC, $valueName, $matches): | |
82 return array($this->resolveName($matches[1]), $matches[2], Mirror::STATIC_PROPERTY | Mirror::PROPERTY); | |
83 | |
84 case !$classOnly && preg_match(self::INSTANCE_MEMBER, $valueName, $matches): | |
85 if ($matches[2] === '->') { | |
86 $kind = Mirror::METHOD | Mirror::PROPERTY; | |
87 } else { | |
88 $kind = Mirror::CONSTANT | Mirror::METHOD; | |
89 } | |
90 | |
91 return array($this->resolveInstance($matches[1]), $matches[3], $kind); | |
92 | |
93 case !$classOnly && preg_match(self::INSTANCE_STATIC, $valueName, $matches): | |
94 return array($this->resolveInstance($matches[1]), $matches[2], Mirror::STATIC_PROPERTY); | |
95 | |
96 default: | |
97 throw new RuntimeException('Unknown target: ' . $valueName); | |
98 } | |
99 } | |
100 | |
101 /** | |
102 * Resolve a class or function name (with the current shell namespace). | |
103 * | |
104 * @param string $name | |
105 * @param bool $includeFunctions (default: false) | |
106 * | |
107 * @return string | |
108 */ | |
109 protected function resolveName($name, $includeFunctions = false) | |
110 { | |
111 if (substr($name, 0, 1) === '\\') { | |
112 return $name; | |
113 } | |
114 | |
115 if ($namespace = $this->getApplication()->getNamespace()) { | |
116 $fullName = $namespace . '\\' . $name; | |
117 | |
118 if (class_exists($fullName) || interface_exists($fullName) || ($includeFunctions && function_exists($fullName))) { | |
119 return $fullName; | |
120 } | |
121 } | |
122 | |
123 return $name; | |
124 } | |
125 | |
126 /** | |
127 * Get a Reflector and documentation for a function, class or instance, constant, method or property. | |
128 * | |
129 * @param string $valueName Function, class, variable, constant, method or property name | |
130 * @param bool $classOnly True if the name should only refer to a class, function or instance | |
131 * | |
132 * @return array (value, Reflector) | |
133 */ | |
134 protected function getTargetAndReflector($valueName, $classOnly = false) | |
135 { | |
136 list($value, $member, $kind) = $this->getTarget($valueName, $classOnly); | |
137 | |
138 return array($value, Mirror::get($value, $member, $kind)); | |
139 } | |
140 | |
141 /** | |
142 * Return a variable instance from the current scope. | |
143 * | |
144 * @throws \InvalidArgumentException when the requested variable does not exist in the current scope | |
145 * | |
146 * @param string $name | |
147 * | |
148 * @return mixed Variable instance | |
149 */ | |
150 protected function resolveInstance($name) | |
151 { | |
152 $value = $this->getScopeVariable($name); | |
153 if (!is_object($value)) { | |
154 throw new RuntimeException('Unable to inspect a non-object'); | |
155 } | |
156 | |
157 return $value; | |
158 } | |
159 | |
160 /** | |
161 * Get a variable from the current shell scope. | |
162 * | |
163 * @param string $name | |
164 * | |
165 * @return mixed | |
166 */ | |
167 protected function getScopeVariable($name) | |
168 { | |
169 return $this->context->get($name); | |
170 } | |
171 | |
172 /** | |
173 * Get all scope variables from the current shell scope. | |
174 * | |
175 * @return array | |
176 */ | |
177 protected function getScopeVariables() | |
178 { | |
179 return $this->context->getAll(); | |
180 } | |
181 | |
182 /** | |
183 * Given a Reflector instance, set command-scope variables in the shell | |
184 * execution context. This is used to inject magic $__class, $__method and | |
185 * $__file variables (as well as a handful of others). | |
186 * | |
187 * @param \Reflector $reflector | |
188 */ | |
189 protected function setCommandScopeVariables(\Reflector $reflector) | |
190 { | |
191 $vars = array(); | |
192 | |
193 switch (get_class($reflector)) { | |
194 case 'ReflectionClass': | |
195 case 'ReflectionObject': | |
196 $vars['__class'] = $reflector->name; | |
197 if ($reflector->inNamespace()) { | |
198 $vars['__namespace'] = $reflector->getNamespaceName(); | |
199 } | |
200 break; | |
201 | |
202 case 'ReflectionMethod': | |
203 $vars['__method'] = sprintf('%s::%s', $reflector->class, $reflector->name); | |
204 $vars['__class'] = $reflector->class; | |
205 $classReflector = $reflector->getDeclaringClass(); | |
206 if ($classReflector->inNamespace()) { | |
207 $vars['__namespace'] = $classReflector->getNamespaceName(); | |
208 } | |
209 break; | |
210 | |
211 case 'ReflectionFunction': | |
212 $vars['__function'] = $reflector->name; | |
213 if ($reflector->inNamespace()) { | |
214 $vars['__namespace'] = $reflector->getNamespaceName(); | |
215 } | |
216 break; | |
217 | |
218 case 'ReflectionGenerator': | |
219 $funcReflector = $reflector->getFunction(); | |
220 $vars['__function'] = $funcReflector->name; | |
221 if ($funcReflector->inNamespace()) { | |
222 $vars['__namespace'] = $funcReflector->getNamespaceName(); | |
223 } | |
224 if ($fileName = $reflector->getExecutingFile()) { | |
225 $vars['__file'] = $fileName; | |
226 $vars['__line'] = $reflector->getExecutingLine(); | |
227 $vars['__dir'] = dirname($fileName); | |
228 } | |
229 break; | |
230 | |
231 case 'ReflectionProperty': | |
232 case 'Psy\Reflection\ReflectionConstant': | |
233 $classReflector = $reflector->getDeclaringClass(); | |
234 $vars['__class'] = $classReflector->name; | |
235 if ($classReflector->inNamespace()) { | |
236 $vars['__namespace'] = $classReflector->getNamespaceName(); | |
237 } | |
238 // no line for these, but this'll do | |
239 if ($fileName = $reflector->getDeclaringClass()->getFileName()) { | |
240 $vars['__file'] = $fileName; | |
241 $vars['__dir'] = dirname($fileName); | |
242 } | |
243 break; | |
244 } | |
245 | |
246 if ($reflector instanceof \ReflectionClass || $reflector instanceof \ReflectionFunctionAbstract) { | |
247 if ($fileName = $reflector->getFileName()) { | |
248 $vars['__file'] = $fileName; | |
249 $vars['__line'] = $reflector->getStartLine(); | |
250 $vars['__dir'] = dirname($fileName); | |
251 } | |
252 } | |
253 | |
254 $this->context->setCommandScopeVariables($vars); | |
255 } | |
256 } |