Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 /*
|
Chris@0
|
4 * This file is part of Psy Shell.
|
Chris@0
|
5 *
|
Chris@0
|
6 * (c) 2012-2017 Justin Hileman
|
Chris@0
|
7 *
|
Chris@0
|
8 * For the full copyright and license information, please view the LICENSE
|
Chris@0
|
9 * file that was distributed with this source code.
|
Chris@0
|
10 */
|
Chris@0
|
11
|
Chris@0
|
12 namespace Psy;
|
Chris@0
|
13
|
Chris@0
|
14 /**
|
Chris@0
|
15 * The Shell execution context.
|
Chris@0
|
16 *
|
Chris@0
|
17 * This class encapsulates the current variables, most recent return value and
|
Chris@0
|
18 * exception, and the current namespace.
|
Chris@0
|
19 */
|
Chris@0
|
20 class Context
|
Chris@0
|
21 {
|
Chris@0
|
22 private static $specialNames = array('_', '_e', '__out', '__psysh__', 'this');
|
Chris@0
|
23
|
Chris@0
|
24 // Whitelist a very limited number of command-scope magic variable names.
|
Chris@0
|
25 // This might be a bad idea, but future me can sort it out.
|
Chris@0
|
26 private static $commandScopeNames = array(
|
Chris@0
|
27 '__function', '__method', '__class', '__namespace', '__file', '__line', '__dir',
|
Chris@0
|
28 );
|
Chris@0
|
29
|
Chris@0
|
30 private $scopeVariables = array();
|
Chris@0
|
31 private $commandScopeVariables = array();
|
Chris@0
|
32 private $returnValue;
|
Chris@0
|
33 private $lastException;
|
Chris@0
|
34 private $lastStdout;
|
Chris@0
|
35 private $boundObject;
|
Chris@0
|
36
|
Chris@0
|
37 /**
|
Chris@0
|
38 * Get a context variable.
|
Chris@0
|
39 *
|
Chris@0
|
40 * @throws InvalidArgumentException If the variable is not found in the current context
|
Chris@0
|
41 *
|
Chris@0
|
42 * @param string $name
|
Chris@0
|
43 *
|
Chris@0
|
44 * @return mixed
|
Chris@0
|
45 */
|
Chris@0
|
46 public function get($name)
|
Chris@0
|
47 {
|
Chris@0
|
48 switch ($name) {
|
Chris@0
|
49 case '_':
|
Chris@0
|
50 return $this->returnValue;
|
Chris@0
|
51
|
Chris@0
|
52 case '_e':
|
Chris@0
|
53 if (isset($this->lastException)) {
|
Chris@0
|
54 return $this->lastException;
|
Chris@0
|
55 }
|
Chris@0
|
56 break;
|
Chris@0
|
57
|
Chris@0
|
58 case '__out':
|
Chris@0
|
59 if (isset($this->lastStdout)) {
|
Chris@0
|
60 return $this->lastStdout;
|
Chris@0
|
61 }
|
Chris@0
|
62 break;
|
Chris@0
|
63
|
Chris@0
|
64 case 'this':
|
Chris@0
|
65 if (isset($this->boundObject)) {
|
Chris@0
|
66 return $this->boundObject;
|
Chris@0
|
67 }
|
Chris@0
|
68 break;
|
Chris@0
|
69
|
Chris@0
|
70 case '__function':
|
Chris@0
|
71 case '__method':
|
Chris@0
|
72 case '__class':
|
Chris@0
|
73 case '__namespace':
|
Chris@0
|
74 case '__file':
|
Chris@0
|
75 case '__line':
|
Chris@0
|
76 case '__dir':
|
Chris@0
|
77 if (array_key_exists($name, $this->commandScopeVariables)) {
|
Chris@0
|
78 return $this->commandScopeVariables[$name];
|
Chris@0
|
79 }
|
Chris@0
|
80 break;
|
Chris@0
|
81
|
Chris@0
|
82 default:
|
Chris@0
|
83 if (array_key_exists($name, $this->scopeVariables)) {
|
Chris@0
|
84 return $this->scopeVariables[$name];
|
Chris@0
|
85 }
|
Chris@0
|
86 break;
|
Chris@0
|
87 }
|
Chris@0
|
88
|
Chris@0
|
89 throw new \InvalidArgumentException('Unknown variable: $' . $name);
|
Chris@0
|
90 }
|
Chris@0
|
91
|
Chris@0
|
92 /**
|
Chris@0
|
93 * Get all defined variables.
|
Chris@0
|
94 *
|
Chris@0
|
95 * @return array
|
Chris@0
|
96 */
|
Chris@0
|
97 public function getAll()
|
Chris@0
|
98 {
|
Chris@0
|
99 return array_merge($this->scopeVariables, $this->getSpecialVariables());
|
Chris@0
|
100 }
|
Chris@0
|
101
|
Chris@0
|
102 /**
|
Chris@0
|
103 * Get all defined magic variables: $_, $_e, $__out, $__class, $__file, etc.
|
Chris@0
|
104 *
|
Chris@0
|
105 * @return array
|
Chris@0
|
106 */
|
Chris@0
|
107 public function getSpecialVariables()
|
Chris@0
|
108 {
|
Chris@0
|
109 $vars = array(
|
Chris@0
|
110 '_' => $this->returnValue,
|
Chris@0
|
111 );
|
Chris@0
|
112
|
Chris@0
|
113 if (isset($this->lastException)) {
|
Chris@0
|
114 $vars['_e'] = $this->lastException;
|
Chris@0
|
115 }
|
Chris@0
|
116
|
Chris@0
|
117 if (isset($this->lastStdout)) {
|
Chris@0
|
118 $vars['__out'] = $this->lastStdout;
|
Chris@0
|
119 }
|
Chris@0
|
120
|
Chris@0
|
121 if (isset($this->boundObject)) {
|
Chris@0
|
122 $vars['this'] = $this->boundObject;
|
Chris@0
|
123 }
|
Chris@0
|
124
|
Chris@0
|
125 return array_merge($vars, $this->commandScopeVariables);
|
Chris@0
|
126 }
|
Chris@0
|
127
|
Chris@0
|
128 /**
|
Chris@0
|
129 * Set all scope variables.
|
Chris@0
|
130 *
|
Chris@0
|
131 * This method does *not* set any of the magic variables: $_, $_e, $__out,
|
Chris@0
|
132 * $__class, $__file, etc.
|
Chris@0
|
133 *
|
Chris@0
|
134 * @param array $vars
|
Chris@0
|
135 */
|
Chris@0
|
136 public function setAll(array $vars)
|
Chris@0
|
137 {
|
Chris@0
|
138 foreach (self::$specialNames as $key) {
|
Chris@0
|
139 unset($vars[$key]);
|
Chris@0
|
140 }
|
Chris@0
|
141
|
Chris@0
|
142 foreach (self::$commandScopeNames as $key) {
|
Chris@0
|
143 unset($vars[$key]);
|
Chris@0
|
144 }
|
Chris@0
|
145
|
Chris@0
|
146 $this->scopeVariables = $vars;
|
Chris@0
|
147 }
|
Chris@0
|
148
|
Chris@0
|
149 /**
|
Chris@0
|
150 * Set the most recent return value.
|
Chris@0
|
151 *
|
Chris@0
|
152 * @param mixed $value
|
Chris@0
|
153 */
|
Chris@0
|
154 public function setReturnValue($value)
|
Chris@0
|
155 {
|
Chris@0
|
156 $this->returnValue = $value;
|
Chris@0
|
157 }
|
Chris@0
|
158
|
Chris@0
|
159 /**
|
Chris@0
|
160 * Get the most recent return value.
|
Chris@0
|
161 *
|
Chris@0
|
162 * @return mixed
|
Chris@0
|
163 */
|
Chris@0
|
164 public function getReturnValue()
|
Chris@0
|
165 {
|
Chris@0
|
166 return $this->returnValue;
|
Chris@0
|
167 }
|
Chris@0
|
168
|
Chris@0
|
169 /**
|
Chris@0
|
170 * Set the most recent Exception.
|
Chris@0
|
171 *
|
Chris@0
|
172 * @param \Exception $e
|
Chris@0
|
173 */
|
Chris@0
|
174 public function setLastException(\Exception $e)
|
Chris@0
|
175 {
|
Chris@0
|
176 $this->lastException = $e;
|
Chris@0
|
177 }
|
Chris@0
|
178
|
Chris@0
|
179 /**
|
Chris@0
|
180 * Get the most recent Exception.
|
Chris@0
|
181 *
|
Chris@0
|
182 * @throws InvalidArgumentException If no Exception has been caught
|
Chris@0
|
183 *
|
Chris@0
|
184 * @return null|Exception
|
Chris@0
|
185 */
|
Chris@0
|
186 public function getLastException()
|
Chris@0
|
187 {
|
Chris@0
|
188 if (!isset($this->lastException)) {
|
Chris@0
|
189 throw new \InvalidArgumentException('No most-recent exception');
|
Chris@0
|
190 }
|
Chris@0
|
191
|
Chris@0
|
192 return $this->lastException;
|
Chris@0
|
193 }
|
Chris@0
|
194
|
Chris@0
|
195 /**
|
Chris@0
|
196 * Set the most recent output from evaluated code.
|
Chris@0
|
197 *
|
Chris@0
|
198 * @param string $lastStdout
|
Chris@0
|
199 */
|
Chris@0
|
200 public function setLastStdout($lastStdout)
|
Chris@0
|
201 {
|
Chris@0
|
202 $this->lastStdout = $lastStdout;
|
Chris@0
|
203 }
|
Chris@0
|
204
|
Chris@0
|
205 /**
|
Chris@0
|
206 * Get the most recent output from evaluated code.
|
Chris@0
|
207 *
|
Chris@0
|
208 * @throws InvalidArgumentException If no output has happened yet
|
Chris@0
|
209 *
|
Chris@0
|
210 * @return null|string
|
Chris@0
|
211 */
|
Chris@0
|
212 public function getLastStdout()
|
Chris@0
|
213 {
|
Chris@0
|
214 if (!isset($this->lastStdout)) {
|
Chris@0
|
215 throw new \InvalidArgumentException('No most-recent output');
|
Chris@0
|
216 }
|
Chris@0
|
217
|
Chris@0
|
218 return $this->lastStdout;
|
Chris@0
|
219 }
|
Chris@0
|
220
|
Chris@0
|
221 /**
|
Chris@0
|
222 * Set the bound object ($this variable) for the interactive shell.
|
Chris@0
|
223 *
|
Chris@0
|
224 * @param object|null $boundObject
|
Chris@0
|
225 */
|
Chris@0
|
226 public function setBoundObject($boundObject)
|
Chris@0
|
227 {
|
Chris@0
|
228 $this->boundObject = is_object($boundObject) ? $boundObject : null;
|
Chris@0
|
229 }
|
Chris@0
|
230
|
Chris@0
|
231 /**
|
Chris@0
|
232 * Get the bound object ($this variable) for the interactive shell.
|
Chris@0
|
233 *
|
Chris@0
|
234 * @return object|null
|
Chris@0
|
235 */
|
Chris@0
|
236 public function getBoundObject()
|
Chris@0
|
237 {
|
Chris@0
|
238 return $this->boundObject;
|
Chris@0
|
239 }
|
Chris@0
|
240
|
Chris@0
|
241 /**
|
Chris@0
|
242 * Set command-scope magic variables: $__class, $__file, etc.
|
Chris@0
|
243 *
|
Chris@0
|
244 * @param array $commandScopeVariables
|
Chris@0
|
245 */
|
Chris@0
|
246 public function setCommandScopeVariables(array $commandScopeVariables)
|
Chris@0
|
247 {
|
Chris@0
|
248 $vars = array();
|
Chris@0
|
249 foreach ($commandScopeVariables as $key => $value) {
|
Chris@0
|
250 // kind of type check
|
Chris@0
|
251 if (is_scalar($value) && in_array($key, self::$commandScopeNames)) {
|
Chris@0
|
252 $vars[$key] = $value;
|
Chris@0
|
253 }
|
Chris@0
|
254 }
|
Chris@0
|
255
|
Chris@0
|
256 $this->commandScopeVariables = $vars;
|
Chris@0
|
257 }
|
Chris@0
|
258
|
Chris@0
|
259 /**
|
Chris@0
|
260 * Get command-scope magic variables: $__class, $__file, etc.
|
Chris@0
|
261 *
|
Chris@0
|
262 * @return array
|
Chris@0
|
263 */
|
Chris@0
|
264 public function getCommandScopeVariables()
|
Chris@0
|
265 {
|
Chris@0
|
266 return $this->commandScopeVariables;
|
Chris@0
|
267 }
|
Chris@0
|
268
|
Chris@0
|
269 /**
|
Chris@0
|
270 * Get unused command-scope magic variables names: __class, __file, etc.
|
Chris@0
|
271 *
|
Chris@0
|
272 * This is used by the shell to unset old command-scope variables after a
|
Chris@0
|
273 * new batch is set.
|
Chris@0
|
274 *
|
Chris@0
|
275 * @return array Array of unused variable names
|
Chris@0
|
276 */
|
Chris@0
|
277 public function getUnusedCommandScopeVariableNames()
|
Chris@0
|
278 {
|
Chris@0
|
279 return array_diff(self::$commandScopeNames, array_keys($this->commandScopeVariables));
|
Chris@0
|
280 }
|
Chris@0
|
281
|
Chris@0
|
282 /**
|
Chris@0
|
283 * Check whether a variable name is a magic variable.
|
Chris@0
|
284 *
|
Chris@0
|
285 * @param string $name
|
Chris@0
|
286 *
|
Chris@0
|
287 * @return bool
|
Chris@0
|
288 */
|
Chris@0
|
289 public static function isSpecialVariableName($name)
|
Chris@0
|
290 {
|
Chris@0
|
291 return in_array($name, self::$specialNames) || in_array($name, self::$commandScopeNames);
|
Chris@0
|
292 }
|
Chris@0
|
293 }
|