Pressroom template verwijderd, website naar root van repo
This commit is contained in:
177
vendor/psy/psysh/src/Psy/ExecutionLoop/ForkingLoop.php
vendored
Normal file
177
vendor/psy/psysh/src/Psy/ExecutionLoop/ForkingLoop.php
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2017 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Psy\ExecutionLoop;
|
||||
|
||||
use Psy\Context;
|
||||
use Psy\Shell;
|
||||
|
||||
/**
|
||||
* A forking version of the Psy Shell execution loop.
|
||||
*
|
||||
* This version is preferred, as it won't die prematurely if user input includes
|
||||
* a fatal error, such as redeclaring a class or function.
|
||||
*/
|
||||
class ForkingLoop extends Loop
|
||||
{
|
||||
private $savegame;
|
||||
|
||||
/**
|
||||
* Run the execution loop.
|
||||
*
|
||||
* Forks into a master and a loop process. The loop process will handle the
|
||||
* evaluation of all instructions, then return its state via a socket upon
|
||||
* completion.
|
||||
*
|
||||
* @param Shell $shell
|
||||
*/
|
||||
public function run(Shell $shell)
|
||||
{
|
||||
list($up, $down) = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);
|
||||
|
||||
if (!$up) {
|
||||
throw new \RuntimeException('Unable to create socket pair.');
|
||||
}
|
||||
|
||||
$pid = pcntl_fork();
|
||||
if ($pid < 0) {
|
||||
throw new \RuntimeException('Unable to start execution loop.');
|
||||
} elseif ($pid > 0) {
|
||||
// This is the main thread. We'll just wait for a while.
|
||||
|
||||
// We won't be needing this one.
|
||||
fclose($up);
|
||||
|
||||
// Wait for a return value from the loop process.
|
||||
$read = array($down);
|
||||
$write = null;
|
||||
$except = null;
|
||||
if (stream_select($read, $write, $except, null) === false) {
|
||||
throw new \RuntimeException('Error waiting for execution loop.');
|
||||
}
|
||||
|
||||
$content = stream_get_contents($down);
|
||||
fclose($down);
|
||||
|
||||
if ($content) {
|
||||
$shell->setScopeVariables(@unserialize($content));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// This is the child process. It's going to do all the work.
|
||||
if (function_exists('setproctitle')) {
|
||||
setproctitle('psysh (loop)');
|
||||
}
|
||||
|
||||
// We won't be needing this one.
|
||||
fclose($down);
|
||||
|
||||
// Let's do some processing.
|
||||
parent::run($shell);
|
||||
|
||||
// Send the scope variables back up to the main thread
|
||||
fwrite($up, $this->serializeReturn($shell->getScopeVariables(false)));
|
||||
fclose($up);
|
||||
|
||||
posix_kill(posix_getpid(), SIGKILL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a savegame at the start of each loop iteration.
|
||||
*/
|
||||
public function beforeLoop()
|
||||
{
|
||||
$this->createSavegame();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up old savegames at the end of each loop iteration.
|
||||
*/
|
||||
public function afterLoop()
|
||||
{
|
||||
// if there's an old savegame hanging around, let's kill it.
|
||||
if (isset($this->savegame)) {
|
||||
posix_kill($this->savegame, SIGKILL);
|
||||
pcntl_signal_dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a savegame fork.
|
||||
*
|
||||
* The savegame contains the current execution state, and can be resumed in
|
||||
* the event that the worker dies unexpectedly (for example, by encountering
|
||||
* a PHP fatal error).
|
||||
*/
|
||||
private function createSavegame()
|
||||
{
|
||||
// the current process will become the savegame
|
||||
$this->savegame = posix_getpid();
|
||||
|
||||
$pid = pcntl_fork();
|
||||
if ($pid < 0) {
|
||||
throw new \RuntimeException('Unable to create savegame fork.');
|
||||
} elseif ($pid > 0) {
|
||||
// we're the savegame now... let's wait and see what happens
|
||||
pcntl_waitpid($pid, $status);
|
||||
|
||||
// worker exited cleanly, let's bail
|
||||
if (!pcntl_wexitstatus($status)) {
|
||||
posix_kill(posix_getpid(), SIGKILL);
|
||||
}
|
||||
|
||||
// worker didn't exit cleanly, we'll need to have another go
|
||||
$this->createSavegame();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize all serializable return values.
|
||||
*
|
||||
* A naïve serialization will run into issues if there is a Closure or
|
||||
* SimpleXMLElement (among other things) in scope when exiting the execution
|
||||
* loop. We'll just ignore these unserializable classes, and serialize what
|
||||
* we can.
|
||||
*
|
||||
* @param array $return
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function serializeReturn(array $return)
|
||||
{
|
||||
$serializable = array();
|
||||
|
||||
foreach ($return as $key => $value) {
|
||||
// No need to return magic variables
|
||||
if (Context::isSpecialVariableName($key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Resources and Closures don't error, but they don't serialize well either.
|
||||
if (is_resource($value) || $value instanceof \Closure) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
@serialize($value);
|
||||
$serializable[$key] = $value;
|
||||
} catch (\Exception $e) {
|
||||
// we'll just ignore this one...
|
||||
} catch (\Throwable $e) {
|
||||
// and this one too...
|
||||
}
|
||||
}
|
||||
|
||||
return @serialize($serializable);
|
||||
}
|
||||
}
|
||||
186
vendor/psy/psysh/src/Psy/ExecutionLoop/Loop.php
vendored
Normal file
186
vendor/psy/psysh/src/Psy/ExecutionLoop/Loop.php
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Psy Shell.
|
||||
*
|
||||
* (c) 2012-2017 Justin Hileman
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Psy\ExecutionLoop;
|
||||
|
||||
use Psy\Configuration;
|
||||
use Psy\Exception\BreakException;
|
||||
use Psy\Exception\ErrorException;
|
||||
use Psy\Exception\ThrowUpException;
|
||||
use Psy\Exception\TypeErrorException;
|
||||
use Psy\Shell;
|
||||
|
||||
/**
|
||||
* The Psy Shell execution loop.
|
||||
*/
|
||||
class Loop
|
||||
{
|
||||
const NOOP_INPUT = 'return null;';
|
||||
|
||||
/**
|
||||
* Loop constructor.
|
||||
*
|
||||
* The non-forking loop doesn't have much use for Configuration, so we'll
|
||||
* just ignore it.
|
||||
*
|
||||
* @param Configuration $config
|
||||
*/
|
||||
public function __construct(Configuration $config)
|
||||
{
|
||||
// don't need this
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the execution loop.
|
||||
*
|
||||
* @throws ThrowUpException if thrown by the `throw-up` command
|
||||
*
|
||||
* @param Shell $shell
|
||||
*/
|
||||
public function run(Shell $shell)
|
||||
{
|
||||
$loop = function ($__psysh__) {
|
||||
// Load user-defined includes
|
||||
set_error_handler(array($__psysh__, 'handleError'));
|
||||
try {
|
||||
foreach ($__psysh__->getIncludes() as $__psysh_include__) {
|
||||
include $__psysh_include__;
|
||||
}
|
||||
} catch (\Exception $_e) {
|
||||
$__psysh__->writeException($_e);
|
||||
}
|
||||
restore_error_handler();
|
||||
unset($__psysh_include__);
|
||||
|
||||
extract($__psysh__->getScopeVariables(false));
|
||||
|
||||
do {
|
||||
$__psysh__->beforeLoop();
|
||||
$__psysh__->setScopeVariables(get_defined_vars());
|
||||
|
||||
try {
|
||||
// read a line, see if we should eval
|
||||
$__psysh__->getInput();
|
||||
|
||||
// evaluate the current code buffer
|
||||
ob_start(
|
||||
array($__psysh__, 'writeStdout'),
|
||||
version_compare(PHP_VERSION, '5.4', '>=') ? 1 : 2
|
||||
);
|
||||
|
||||
// Let PsySH inject some magic variables back into the
|
||||
// shell scope... things like $__class, and $__file set by
|
||||
// reflection commands
|
||||
extract($__psysh__->getSpecialScopeVariables(false));
|
||||
|
||||
// And unset any magic variables which are no longer needed
|
||||
foreach ($__psysh__->getUnusedCommandScopeVariableNames() as $__psysh_var_name__) {
|
||||
unset($$__psysh_var_name__, $__psysh_var_name__);
|
||||
}
|
||||
|
||||
set_error_handler(array($__psysh__, 'handleError'));
|
||||
$_ = eval($__psysh__->flushCode() ?: Loop::NOOP_INPUT);
|
||||
restore_error_handler();
|
||||
|
||||
ob_end_flush();
|
||||
|
||||
$__psysh__->writeReturnValue($_);
|
||||
} catch (BreakException $_e) {
|
||||
restore_error_handler();
|
||||
if (ob_get_level() > 0) {
|
||||
ob_end_clean();
|
||||
}
|
||||
$__psysh__->writeException($_e);
|
||||
|
||||
return;
|
||||
} catch (ThrowUpException $_e) {
|
||||
restore_error_handler();
|
||||
if (ob_get_level() > 0) {
|
||||
ob_end_clean();
|
||||
}
|
||||
$__psysh__->writeException($_e);
|
||||
|
||||
throw $_e;
|
||||
} catch (\TypeError $_e) {
|
||||
restore_error_handler();
|
||||
if (ob_get_level() > 0) {
|
||||
ob_end_clean();
|
||||
}
|
||||
$__psysh__->writeException(TypeErrorException::fromTypeError($_e));
|
||||
} catch (\Error $_e) {
|
||||
restore_error_handler();
|
||||
if (ob_get_level() > 0) {
|
||||
ob_end_clean();
|
||||
}
|
||||
$__psysh__->writeException(ErrorException::fromError($_e));
|
||||
} catch (\Exception $_e) {
|
||||
restore_error_handler();
|
||||
if (ob_get_level() > 0) {
|
||||
ob_end_clean();
|
||||
}
|
||||
$__psysh__->writeException($_e);
|
||||
}
|
||||
|
||||
$__psysh__->afterLoop();
|
||||
} while (true);
|
||||
};
|
||||
|
||||
// bind the closure to $this from the shell scope variables...
|
||||
if (self::bindLoop()) {
|
||||
$that = $shell->getBoundObject();
|
||||
if (is_object($that)) {
|
||||
$loop = $loop->bindTo($that, get_class($that));
|
||||
} else {
|
||||
$loop = $loop->bindTo(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
$loop($shell);
|
||||
}
|
||||
|
||||
/**
|
||||
* A beforeLoop callback.
|
||||
*
|
||||
* This is executed at the start of each loop iteration. In the default
|
||||
* (non-forking) loop implementation, this is a no-op.
|
||||
*/
|
||||
public function beforeLoop()
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
/**
|
||||
* A afterLoop callback.
|
||||
*
|
||||
* This is executed at the end of each loop iteration. In the default
|
||||
* (non-forking) loop implementation, this is a no-op.
|
||||
*/
|
||||
public function afterLoop()
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
/**
|
||||
* Decide whether to bind the execution loop.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function bindLoop()
|
||||
{
|
||||
// skip binding on HHVM <= 3.5.0
|
||||
// see https://github.com/facebook/hhvm/issues/1203
|
||||
if (defined('HHVM_VERSION')) {
|
||||
return version_compare(HHVM_VERSION, '3.5.0', '>=');
|
||||
}
|
||||
|
||||
return version_compare(PHP_VERSION, '5.4', '>=');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user