Chris@13: setClosure($__psysh__, function () use ($__psysh__) { Chris@13: try { Chris@13: // Restore execution scope variables Chris@13: extract($__psysh__->getScopeVariables(false)); Chris@13: Chris@13: // Buffer stdout; we'll need it later Chris@13: ob_start([$__psysh__, 'writeStdout'], 1); Chris@13: Chris@13: // Convert all errors to exceptions Chris@13: 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@13: restore_error_handler(); Chris@13: if (ob_get_level() > 0) { Chris@13: 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@13: restore_error_handler(); Chris@13: if (ob_get_level() > 0) { Chris@13: ob_end_clean(); Chris@13: } Chris@13: Chris@13: throw $_e; Chris@13: } Chris@13: Chris@13: // Won't be needing this anymore Chris@13: restore_error_handler(); Chris@13: Chris@13: // Flush stdout (write to shell output, plus save to magic variable) Chris@13: ob_end_flush(); Chris@13: Chris@13: // Save execution scope variables for next time Chris@13: $__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@13: if (is_object($that)) { Chris@16: $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@13: if (defined('HHVM_VERSION')) { Chris@13: return version_compare(HHVM_VERSION, '3.5.0', '>='); Chris@13: } Chris@13: Chris@13: return true; Chris@13: } Chris@13: }