4 * This file is part of Psy Shell.
6 * (c) 2012-2018 Justin Hileman
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
15 * The Shell execution context.
17 * This class encapsulates the current variables, most recent return value and
18 * exception, and the current namespace.
22 private static $specialNames = ['_', '_e', '__out', '__psysh__', 'this'];
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',
30 private $scopeVariables = [];
31 private $commandScopeVariables = [];
33 private $lastException;
39 * Get a context variable.
41 * @throws InvalidArgumentException If the variable is not found in the current context
47 public function get($name)
51 return $this->returnValue;
54 if (isset($this->lastException)) {
55 return $this->lastException;
60 if (isset($this->lastStdout)) {
61 return $this->lastStdout;
66 if (isset($this->boundObject)) {
67 return $this->boundObject;
78 if (array_key_exists($name, $this->commandScopeVariables)) {
79 return $this->commandScopeVariables[$name];
84 if (array_key_exists($name, $this->scopeVariables)) {
85 return $this->scopeVariables[$name];
90 throw new \InvalidArgumentException('Unknown variable: $' . $name);
94 * Get all defined variables.
98 public function getAll()
100 return array_merge($this->scopeVariables, $this->getSpecialVariables());
104 * Get all defined magic variables: $_, $_e, $__out, $__class, $__file, etc.
108 public function getSpecialVariables()
111 '_' => $this->returnValue,
114 if (isset($this->lastException)) {
115 $vars['_e'] = $this->lastException;
118 if (isset($this->lastStdout)) {
119 $vars['__out'] = $this->lastStdout;
122 if (isset($this->boundObject)) {
123 $vars['this'] = $this->boundObject;
126 return array_merge($vars, $this->commandScopeVariables);
130 * Set all scope variables.
132 * This method does *not* set any of the magic variables: $_, $_e, $__out,
133 * $__class, $__file, etc.
137 public function setAll(array $vars)
139 foreach (self::$specialNames as $key) {
143 foreach (self::$commandScopeNames as $key) {
147 $this->scopeVariables = $vars;
151 * Set the most recent return value.
153 * @param mixed $value
155 public function setReturnValue($value)
157 $this->returnValue = $value;
161 * Get the most recent return value.
165 public function getReturnValue()
167 return $this->returnValue;
171 * Set the most recent Exception.
173 * @param \Exception $e
175 public function setLastException(\Exception $e)
177 $this->lastException = $e;
181 * Get the most recent Exception.
183 * @throws \InvalidArgumentException If no Exception has been caught
185 * @return null|\Exception
187 public function getLastException()
189 if (!isset($this->lastException)) {
190 throw new \InvalidArgumentException('No most-recent exception');
193 return $this->lastException;
197 * Set the most recent output from evaluated code.
199 * @param string $lastStdout
201 public function setLastStdout($lastStdout)
203 $this->lastStdout = $lastStdout;
207 * Get the most recent output from evaluated code.
209 * @throws \InvalidArgumentException If no output has happened yet
211 * @return null|string
213 public function getLastStdout()
215 if (!isset($this->lastStdout)) {
216 throw new \InvalidArgumentException('No most-recent output');
219 return $this->lastStdout;
223 * Set the bound object ($this variable) for the interactive shell.
225 * Note that this unsets the bound class, if any exists.
227 * @param object|null $boundObject
229 public function setBoundObject($boundObject)
231 $this->boundObject = is_object($boundObject) ? $boundObject : null;
232 $this->boundClass = null;
236 * Get the bound object ($this variable) for the interactive shell.
238 * @return object|null
240 public function getBoundObject()
242 return $this->boundObject;
246 * Set the bound class (self) for the interactive shell.
248 * Note that this unsets the bound object, if any exists.
250 * @param string|null $boundClass
252 public function setBoundClass($boundClass)
254 $this->boundClass = (is_string($boundClass) && $boundClass !== '') ? $boundClass : null;
255 $this->boundObject = null;
259 * Get the bound class (self) for the interactive shell.
261 * @return string|null
263 public function getBoundClass()
265 return $this->boundClass;
269 * Set command-scope magic variables: $__class, $__file, etc.
271 * @param array $commandScopeVariables
273 public function setCommandScopeVariables(array $commandScopeVariables)
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;
283 $this->commandScopeVariables = $vars;
287 * Get command-scope magic variables: $__class, $__file, etc.
291 public function getCommandScopeVariables()
293 return $this->commandScopeVariables;
297 * Get unused command-scope magic variables names: __class, __file, etc.
299 * This is used by the shell to unset old command-scope variables after a
302 * @return array Array of unused variable names
304 public function getUnusedCommandScopeVariableNames()
306 return array_diff(self::$commandScopeNames, array_keys($this->commandScopeVariables));
310 * Check whether a variable name is a magic variable.
312 * @param string $name
316 public static function isSpecialVariableName($name)
318 return in_array($name, self::$specialNames) || in_array($name, self::$commandScopeNames);