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