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