annotate vendor/psy/psysh/src/ExecutionClosure.php @ 4:a9cd425dd02b

Update, including to Drupal core 8.6.10
author Chris Cannam
date Thu, 28 Feb 2019 13:11:55 +0000
parents c75dbcec494b
children
rev   line source
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-2018 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 Psy Shell's execution scope.
Chris@0 16 */
Chris@0 17 class ExecutionClosure
Chris@0 18 {
Chris@0 19 const NOOP_INPUT = 'return null;';
Chris@0 20
Chris@0 21 private $closure;
Chris@0 22
Chris@0 23 /**
Chris@0 24 * @param Shell $__psysh__
Chris@0 25 */
Chris@0 26 public function __construct(Shell $__psysh__)
Chris@0 27 {
Chris@0 28 $this->setClosure($__psysh__, function () use ($__psysh__) {
Chris@0 29 try {
Chris@0 30 // Restore execution scope variables
Chris@4 31 \extract($__psysh__->getScopeVariables(false));
Chris@0 32
Chris@0 33 // Buffer stdout; we'll need it later
Chris@4 34 \ob_start([$__psysh__, 'writeStdout'], 1);
Chris@0 35
Chris@0 36 // Convert all errors to exceptions
Chris@4 37 \set_error_handler([$__psysh__, 'handleError']);
Chris@0 38
Chris@0 39 // Evaluate the current code buffer
Chris@0 40 $_ = eval($__psysh__->onExecute($__psysh__->flushCode() ?: ExecutionClosure::NOOP_INPUT));
Chris@0 41 } catch (\Throwable $_e) {
Chris@0 42 // Clean up on our way out.
Chris@4 43 \restore_error_handler();
Chris@4 44 if (\ob_get_level() > 0) {
Chris@4 45 \ob_end_clean();
Chris@0 46 }
Chris@0 47
Chris@0 48 throw $_e;
Chris@0 49 } catch (\Exception $_e) {
Chris@0 50 // Clean up on our way out.
Chris@4 51 \restore_error_handler();
Chris@4 52 if (\ob_get_level() > 0) {
Chris@4 53 \ob_end_clean();
Chris@0 54 }
Chris@0 55
Chris@0 56 throw $_e;
Chris@0 57 }
Chris@0 58
Chris@0 59 // Won't be needing this anymore
Chris@4 60 \restore_error_handler();
Chris@0 61
Chris@0 62 // Flush stdout (write to shell output, plus save to magic variable)
Chris@4 63 \ob_end_flush();
Chris@0 64
Chris@0 65 // Save execution scope variables for next time
Chris@4 66 $__psysh__->setScopeVariables(\get_defined_vars());
Chris@0 67
Chris@0 68 return $_;
Chris@0 69 });
Chris@0 70 }
Chris@0 71
Chris@0 72 /**
Chris@0 73 * Set the closure instance.
Chris@0 74 *
Chris@0 75 * @param Shell $psysh
Chris@0 76 * @param \Closure $closure
Chris@0 77 */
Chris@0 78 protected function setClosure(Shell $shell, \Closure $closure)
Chris@0 79 {
Chris@0 80 if (self::shouldBindClosure()) {
Chris@0 81 $that = $shell->getBoundObject();
Chris@4 82 if (\is_object($that)) {
Chris@4 83 $closure = $closure->bindTo($that, \get_class($that));
Chris@0 84 } else {
Chris@0 85 $closure = $closure->bindTo(null, $shell->getBoundClass());
Chris@0 86 }
Chris@0 87 }
Chris@0 88
Chris@0 89 $this->closure = $closure;
Chris@0 90 }
Chris@0 91
Chris@0 92 /**
Chris@0 93 * Go go gadget closure.
Chris@0 94 *
Chris@0 95 * @return mixed
Chris@0 96 */
Chris@0 97 public function execute()
Chris@0 98 {
Chris@0 99 $closure = $this->closure;
Chris@0 100
Chris@0 101 return $closure();
Chris@0 102 }
Chris@0 103
Chris@0 104 /**
Chris@0 105 * Decide whether to bind the execution closure.
Chris@0 106 *
Chris@0 107 * @return bool
Chris@0 108 */
Chris@0 109 protected static function shouldBindClosure()
Chris@0 110 {
Chris@0 111 // skip binding on HHVM < 3.5.0
Chris@0 112 // see https://github.com/facebook/hhvm/issues/1203
Chris@4 113 if (\defined('HHVM_VERSION')) {
Chris@4 114 return \version_compare(HHVM_VERSION, '3.5.0', '>=');
Chris@0 115 }
Chris@0 116
Chris@0 117 return true;
Chris@0 118 }
Chris@0 119 }