Chris@13: setClosure($__psysh__, function () use ($__psysh__) { Chris@13: try { Chris@13: // Restore execution scope variables Chris@17: \extract($__psysh__->getScopeVariables(false)); Chris@13: Chris@13: // Buffer stdout; we'll need it later Chris@17: \ob_start([$__psysh__, 'writeStdout'], 1); Chris@13: Chris@13: // Convert all errors to exceptions Chris@17: \set_error_handler([$__psysh__, 'handleError']); Chris@13: Chris@13: // Evaluate the current code buffer Chris@13: $_ = eval($__psysh__->onExecute($__psysh__->flushCode() ?: ExecutionClosure::NOOP_INPUT)); Chris@13: } catch (\Throwable $_e) { Chris@13: // Clean up on our way out. Chris@17: \restore_error_handler(); Chris@17: if (\ob_get_level() > 0) { Chris@17: \ob_end_clean(); Chris@13: } Chris@13: Chris@13: throw $_e; Chris@13: } catch (\Exception $_e) { Chris@13: // Clean up on our way out. Chris@17: \restore_error_handler(); Chris@17: if (\ob_get_level() > 0) { Chris@17: \ob_end_clean(); Chris@13: } Chris@13: Chris@13: throw $_e; Chris@13: } Chris@13: Chris@13: // Won't be needing this anymore Chris@17: \restore_error_handler(); Chris@13: Chris@13: // Flush stdout (write to shell output, plus save to magic variable) Chris@17: \ob_end_flush(); Chris@13: Chris@13: // Save execution scope variables for next time Chris@17: $__psysh__->setScopeVariables(\get_defined_vars()); Chris@13: Chris@13: return $_; Chris@16: }); Chris@16: } Chris@13: Chris@16: /** Chris@16: * Set the closure instance. Chris@16: * Chris@16: * @param Shell $psysh Chris@16: * @param \Closure $closure Chris@16: */ Chris@16: protected function setClosure(Shell $shell, \Closure $closure) Chris@16: { Chris@13: if (self::shouldBindClosure()) { Chris@16: $that = $shell->getBoundObject(); Chris@17: if (\is_object($that)) { Chris@17: $closure = $closure->bindTo($that, \get_class($that)); Chris@13: } else { Chris@16: $closure = $closure->bindTo(null, $shell->getBoundClass()); Chris@13: } Chris@13: } Chris@13: Chris@16: $this->closure = $closure; Chris@13: } Chris@13: Chris@13: /** Chris@13: * Go go gadget closure. Chris@13: * Chris@13: * @return mixed Chris@13: */ Chris@13: public function execute() Chris@13: { Chris@13: $closure = $this->closure; Chris@13: Chris@13: return $closure(); Chris@13: } Chris@13: Chris@13: /** Chris@13: * Decide whether to bind the execution closure. Chris@13: * Chris@13: * @return bool Chris@13: */ Chris@13: protected static function shouldBindClosure() Chris@13: { Chris@13: // skip binding on HHVM < 3.5.0 Chris@13: // see https://github.com/facebook/hhvm/issues/1203 Chris@17: if (\defined('HHVM_VERSION')) { Chris@17: return \version_compare(HHVM_VERSION, '3.5.0', '>='); Chris@13: } Chris@13: Chris@13: return true; Chris@13: } Chris@13: }