From f55f32eff7b894c9518218fbe1e1d98b87c53f98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20FRAN=C3=87OIS?= Date: Thu, 15 Dec 2016 20:10:17 +0100 Subject: [PATCH 1/4] Basic completion --- lib/Boris/EvalWorker.php | 78 +++++++++++++++++++-- lib/Boris/ReadlineClient.php | 132 ++++++++++++++++++++++++++++++++++- 2 files changed, 204 insertions(+), 6 deletions(-) diff --git a/lib/Boris/EvalWorker.php b/lib/Boris/EvalWorker.php index 0792d09..e9cd4f3 100644 --- a/lib/Boris/EvalWorker.php +++ b/lib/Boris/EvalWorker.php @@ -12,6 +12,25 @@ class EvalWorker const EXITED = "\1"; const FAILED = "\2"; const READY = "\3"; + + const D_VARS = 'vars'; + const D_VARS_TYPE = 'type'; + const D_VARS_CLASS = 'class'; + const D_CLASSES = 'classes'; + const D_FUNCTIONS = 'functions'; + + const INTERNAL_VARS = [ + 'baseVars' => true, + '__scope' => true, + 'hooks' => true, + '__hook' => true, + '__input' => true, + '__response' => true, + '__oldexh' => true, + '__pid' => true, + '__result' => true, + '__hasError' => true, + ]; private $_socket; private $_exports = array(); @@ -22,7 +41,7 @@ class EvalWorker private $_cancelled; private $_inspector; private $_userExceptionHandler; - + /** * Create a new worker using the given socket for communication. * @@ -89,11 +108,13 @@ public function setInspector($inspector) */ public function start() { + $baseVars = get_defined_vars(); + $__scope = $this->_runHooks($this->_startHooks); extract($__scope); $this->_write($this->_socket, self::READY); - + $this->_sendDeclaredStuff($this->_socket, $baseVars, get_defined_vars()); /* Note the naming of the local variables due to shared scope with the user here */ for (;;) { declare (ticks = 1); @@ -148,8 +169,19 @@ public function start() // undo ctrl-c signal handling ready for user code execution pcntl_signal(SIGINT, SIG_DFL, true); $__pid = posix_getpid(); - - $__result = eval($__input); + + $__result = null; + $__hasError = false; + try { + $__result = eval($__input); + } catch(\Throwable $t) { + $__hasError = true; + while($t) { + fwrite(STDERR, $t->getMessage().PHP_EOL); + fwrite(STDERR, $t->getTraceAsString().PHP_EOL); + $t = $t->getPrevious(); + } + } if (posix_getpid() != $__pid) { // whatever the user entered caused a forked child @@ -157,7 +189,7 @@ public function start() exit(0); } - if (preg_match('/\s*return\b/i', $__input)) { + if (!$__hasError && preg_match('/\s*return\b/i', $__input)) { fwrite(STDOUT, sprintf("%s\n", $this->_inspector->inspect($__result))); } $this->_expungeOldWorker(); @@ -168,6 +200,10 @@ public function start() if ($__response == self::EXITED) { exit(0); } + if($__response == self::DONE) { + $this->_sendDeclaredStuff($this->_socket, $baseVars, get_defined_vars()); + } + } } @@ -242,6 +278,8 @@ private function _read($socket) throw new \UnexpectedValueException("Socket error: closed"); } } + + return null; } private function _select(&$read, &$except) @@ -272,4 +310,34 @@ private function _transform($input) return $input; } + + private function _sendDeclaredStuff($socket, $baseVars, $get_defined_vars) + { + $declaredStuff = [ + self::D_VARS => [], + self::D_CLASSES => [] + ]; + + foreach(array_merge($GLOBALS, $get_defined_vars) as $name => $var) { + + if(isset($baseVars[$name]) || isset(self::INTERNAL_VARS[$name])) continue; + + $type = gettype($var); + + $declaredStuff[self::D_VARS][$name] = [ + self::D_VARS_TYPE => $type + ]; + if(is_object($var)) { + $declaredStuff[self::D_VARS][$name][self::D_VARS_CLASS] = get_class($var); + } + } + + foreach(array_merge(get_declared_classes(), get_declared_interfaces(), get_declared_traits()) as $cls) { + $declaredStuff[self::D_CLASSES][$cls] = true; + } + + $declaredStuff[self::D_FUNCTIONS] = get_defined_functions(); + + $this->_write($socket, json_encode($declaredStuff)."\n"); + } } diff --git a/lib/Boris/ReadlineClient.php b/lib/Boris/ReadlineClient.php index 7cd8fd7..9310c84 100644 --- a/lib/Boris/ReadlineClient.php +++ b/lib/Boris/ReadlineClient.php @@ -13,6 +13,15 @@ class ReadlineClient private $_prompt; private $_historyFile; private $_clear = false; + + private $_vars = [ + EvalWorker::D_VARS => [], + EvalWorker::D_CLASSES => [], + EvalWorker::D_FUNCTIONS => [ + 'internal' => [], + 'user' => [] + ] + ]; /** * Create a new ReadlineClient using $socket for communication. @@ -42,11 +51,15 @@ public function start($prompt, $historyFile) $this, 'clear' ), true); + + readline_completion_function($this->_getReadlineCompletionFunction($this->_vars)); // wait for the worker to finish executing hooks if (fread($this->_socket, 1) != EvalWorker::READY) { throw new \RuntimeException('EvalWorker failed to start'); } + + $this->_readVars(); $parser = new ShallowParser(); $buf = ''; @@ -55,7 +68,7 @@ public function start($prompt, $historyFile) for (;;) { $this->_clear = false; $line = readline(sprintf('[%d] %s', $lineno, ($buf == '' ? $prompt : str_pad('*> ', strlen($prompt), ' ', STR_PAD_LEFT)))); - + if ($this->_clear) { $buf = ''; continue; @@ -88,6 +101,8 @@ public function start($prompt, $historyFile) exit(0); } elseif ($status == EvalWorker::FAILED) { break; + } elseif($status == EvalWorker::DONE) { + $this->_readVars(); } } } @@ -103,4 +118,119 @@ public function clear() // FIXME: I'd love to have this send \r to readline so it puts the user on a blank line $this->_clear = true; } + + private function _readVars() { + $vars = ""; + while(true) { + $tmp = fread($this->_socket, 1); + if($tmp === false || $tmp == "\n") { + break; + } + $vars .= $tmp; + } + $this->_vars = json_decode($vars, true); + } + + + private function _getReadlineCompletionFunction(&$local) { + return function() use (&$local) { + // Get the full input buffer so we can use some context when suggesting things. + $info = readline_info(); + $input = substr($info['line_buffer'], 0, $info['end']); + $return = array(); + // Accessing a class method or property + if(preg_match('/\$([a-zA-Z0-9_]+)\->[a-zA-Z0-9_]*$/', $input, $m)) { + $var = $m[1]; + $varValue = null; + + if(isset($local[EvalWorker::D_VARS][$var])) { + $varValue = $local[EvalWorker::D_VARS][$var]; + } + + if($varValue !== null && $varValue[EvalWorker::D_VARS_TYPE] == 'object') { + $refl = new \ReflectionClass($varValue[EvalWorker::D_VARS_CLASS]); + $methods = $refl->getMethods(\ReflectionMethod::IS_PUBLIC); + foreach($methods as $method) { + $return[] = $method->name . '('; + } + $properties = $refl->getProperties(\ReflectionProperty::IS_PUBLIC); + foreach($properties as $property) { + $return[] = $property->name; + } + } + } // Are we trying to auto complete a static class method, constant or property? + else if(preg_match('/\$?([a-zA-Z0-9_\\\\]+)::(\$?)([a-zA-Z0-9_])*$/', $input, $m)) { + $class = $m[1]; + $refl = null; + + if(class_exists($class)) { + $refl = new \ReflectionClass($class); + } else if(isset($GLOBALS[$class]) && is_object($GLOBALS[$class])) { + $refl = new \ReflectionClass($GLOBALS[$class]); + } + if(!is_null($refl)) { + $exploded = explode('\\', $class); + $class = array_pop($exploded); + if(empty($m[2])) { + $methods = $refl->getMethods(\ReflectionMethod::IS_STATIC); + foreach($methods as $method) { + if($method->isPublic()) { + $return[] = $class . '::' . $method->name . '('; + } + } + $constants = $refl->getConstants(); + foreach($constants as $constant => $value) { + $return[] = $class . '::' . $constant; + } + $return[] = $class.'::class'; + } + if(!empty($m[2]) || empty($m[3])) { + $properties = $refl->getProperties(\ReflectionProperty::IS_STATIC); + foreach($properties as $property) { + if($property->isPublic()) { + $return[] = $class . '::$' . $property->name; + } + } + } + } + } else if(preg_match('/\\\\([a-zA-Z0-9_\\\\]+)$/', $input, $m)) { + $match = $m[1]; + $exploded = explode('\\', $match); + $lastComponentIndex = count($exploded) - 1; + if($lastComponentIndex == -1) { + return false; + } + $comp = []; + foreach(array_keys($this->_vars[EvalWorker::D_CLASSES]) as $cl) { + if(strncmp($match, $cl, strlen($match)) == 0) { + $clExploded = explode('\\', $cl); + array_splice($clExploded, 0, $lastComponentIndex); + $comp[implode('\\', $clExploded)] = true; + } + } + + $return = array_keys($comp); + + } else if(preg_match('/\'[^\']*$/', $input) || preg_match('/"[^"]*$/', $input)) { + return false; // This makes readline auto-complete files + } else if(preg_match('/\$[a-zA-Z0-9_]*$/', $input)) { + $return = array_keys($local[EvalWorker::D_VARS]); + } else { + $functions = $local[EvalWorker::D_FUNCTIONS]; + $classes = $local[EvalWorker::D_CLASSES]; + $functions['internal'] = array_map(function($v) { + return $v . '('; + }, $functions['internal']); + + $functions['user'] = array_map(function($v) { + return $v . '('; + }, $functions['user']); + $return = array_merge($return, $classes, $functions['user'], $functions['internal'], array('require ', 'echo ')); + } + if(empty($return)) { + return array(''); + } + return $return; + }; + } } From fc0d35cb9a11f81ab33c16843ff58c2b408f3186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20FRAN=C3=87OIS?= Date: Mon, 19 Dec 2016 11:01:07 +0100 Subject: [PATCH 2/4] delegate completion to EvalWorker --- lib/Boris/EvalWorker.php | 146 ++++++++++++++++++++++++------- lib/Boris/ReadlineClient.php | 161 +++++++++-------------------------- 2 files changed, 156 insertions(+), 151 deletions(-) diff --git a/lib/Boris/EvalWorker.php b/lib/Boris/EvalWorker.php index e9cd4f3..54a753f 100644 --- a/lib/Boris/EvalWorker.php +++ b/lib/Boris/EvalWorker.php @@ -13,6 +13,10 @@ class EvalWorker const FAILED = "\2"; const READY = "\3"; + const CMD_EVAL = "\0"; + const CMD_COMPLETE = "\1"; + + const D_VARS = 'vars'; const D_VARS_TYPE = 'type'; const D_VARS_CLASS = 'class'; @@ -108,13 +112,11 @@ public function setInspector($inspector) */ public function start() { - $baseVars = get_defined_vars(); $__scope = $this->_runHooks($this->_startHooks); extract($__scope); $this->_write($this->_socket, self::READY); - $this->_sendDeclaredStuff($this->_socket, $baseVars, get_defined_vars()); /* Note the naming of the local variables due to shared scope with the user here */ for (;;) { declare (ticks = 1); @@ -123,7 +125,24 @@ public function start() $this->_cancelled = false; - $__input = $this->_transform($this->_read($this->_socket)); + list($cmd, $data) = $this->_read($this->_socket); + + if($cmd == self::CMD_COMPLETE) { + $vars = array_filter( + get_defined_vars(), + function($var) { + return !isset(EvalWorker::INTERNAL_VARS[$var]); + }, + ARRAY_FILTER_USE_KEY); + $this->_write( + $this->_socket, + json_encode($this->_complete($vars, $data))); + continue; + } else if($cmd != self::CMD_EVAL) { + //ignore unknown commands + continue; + } + $__input = $this->_transform($data); if ($__input === null) { continue; @@ -200,10 +219,6 @@ public function start() if ($__response == self::EXITED) { exit(0); } - if($__response == self::DONE) { - $this->_sendDeclaredStuff($this->_socket, $baseVars, get_defined_vars()); - } - } } @@ -273,13 +288,14 @@ private function _read($socket) if ($this->_select($read, $except) > 0) { if ($read) { - return stream_get_contents($read[0]); + $cmd = stream_get_contents($read[0], 1); + return [$cmd, stream_get_contents($read[0])]; } else if ($except) { throw new \UnexpectedValueException("Socket error: closed"); } } - return null; + return [null, null]; } private function _select(&$read, &$except) @@ -311,33 +327,103 @@ private function _transform($input) return $input; } - private function _sendDeclaredStuff($socket, $baseVars, $get_defined_vars) - { - $declaredStuff = [ - self::D_VARS => [], - self::D_CLASSES => [] - ]; - - foreach(array_merge($GLOBALS, $get_defined_vars) as $name => $var) { + private function _complete($declaredStuff, $input) { + // Accessing a class method or property + if(preg_match('/\$([a-zA-Z0-9_]+)\->[a-zA-Z0-9_]*$/', $input, $m)) { + $var = $m[1]; + $varValue = null; - if(isset($baseVars[$name]) || isset(self::INTERNAL_VARS[$name])) continue; + if(isset($declaredStuff[$var])) { + $varValue = $declaredStuff[$var]; + } else if(isset($GLOBALS[$var])) { + $varValue = $GLOBALS[$var]; + } - $type = gettype($var); + if($varValue !== null && is_object($varValue)) { + $refl = new \ReflectionClass($varValue); + $methods = $refl->getMethods(\ReflectionMethod::IS_PUBLIC); + foreach($methods as $method) { + if($method->name != '__construct') { + $return[] = $method->name . '('; + } + } + $properties = $refl->getProperties(\ReflectionProperty::IS_PUBLIC); + foreach($properties as $property) { + $return[] = $property->name; + } + } + } // Are we trying to auto complete a static class method, constant or property? + else if(preg_match('/\$?([a-zA-Z0-9_\\\\]+)::(\$?)([a-zA-Z0-9_])*$/', $input, $m)) { + $class = $m[1]; + $refl = null; - $declaredStuff[self::D_VARS][$name] = [ - self::D_VARS_TYPE => $type - ]; - if(is_object($var)) { - $declaredStuff[self::D_VARS][$name][self::D_VARS_CLASS] = get_class($var); + if(class_exists($class)) { + $refl = new \ReflectionClass($class); + } else if(isset($GLOBALS[$class]) && is_object($GLOBALS[$class])) { + $refl = new \ReflectionClass($GLOBALS[$class]); + } + if(!is_null($refl)) { + $exploded = explode('\\', $class); + $class = array_pop($exploded); + if(empty($m[2])) { + $methods = $refl->getMethods(\ReflectionMethod::IS_STATIC); + foreach($methods as $method) { + if($method->isPublic()) { + $return[] = $class . '::' . $method->name . '('; + } + } + $constants = $refl->getConstants(); + foreach($constants as $constant => $value) { + $return[] = $class . '::' . $constant; + } + $return[] = $class.'::class'; + } + if(!empty($m[2]) || empty($m[3])) { + $properties = $refl->getProperties(\ReflectionProperty::IS_STATIC); + foreach($properties as $property) { + if($property->isPublic()) { + $return[] = $class . '::$' . $property->name; + } + } + } + } + } else if(preg_match('/\\\\([a-zA-Z0-9_\\\\]+)$/', $input, $m)) { + $match = $m[1]; + $exploded = explode('\\', $match); + $lastComponentIndex = count($exploded) - 1; + if($lastComponentIndex == -1) { + return false; + } + $comp = []; + foreach(get_declared_classes() as $cl) { + if(strncmp($match, $cl, strlen($match)) == 0) { + $clExploded = explode('\\', $cl); + array_splice($clExploded, 0, $lastComponentIndex); + $comp[implode('\\', $clExploded)] = true; + } } - } - foreach(array_merge(get_declared_classes(), get_declared_interfaces(), get_declared_traits()) as $cls) { - $declaredStuff[self::D_CLASSES][$cls] = true; - } + $return = array_keys($comp); - $declaredStuff[self::D_FUNCTIONS] = get_defined_functions(); + } else if(preg_match('/\'[^\']*$/', $input) || preg_match('/"[^"]*$/', $input)) { + return false; // This makes readline auto-complete files + } else if(preg_match('/\$[a-zA-Z0-9_]*$/', $input)) { + $return = array_merge(array_keys($declaredStuff), array_keys($GLOBALS)); + } else { + $functions = get_defined_functions(); + $classes = get_declared_classes(); + $functions['internal'] = array_map(function($v) { + return $v . '('; + }, $functions['internal']); - $this->_write($socket, json_encode($declaredStuff)."\n"); + $functions['user'] = array_map(function($v) { + return $v . '('; + }, $functions['user']); + $return = array_merge($classes, $functions['user'], $functions['internal'], array('require ', 'echo ')); + } + if(empty($return)) { + return array(''); + } + return $return; } } diff --git a/lib/Boris/ReadlineClient.php b/lib/Boris/ReadlineClient.php index 9310c84..b118add 100644 --- a/lib/Boris/ReadlineClient.php +++ b/lib/Boris/ReadlineClient.php @@ -10,19 +10,8 @@ class ReadlineClient { private $_socket; - private $_prompt; - private $_historyFile; private $_clear = false; - private $_vars = [ - EvalWorker::D_VARS => [], - EvalWorker::D_CLASSES => [], - EvalWorker::D_FUNCTIONS => [ - 'internal' => [], - 'user' => [] - ] - ]; - /** * Create a new ReadlineClient using $socket for communication. * @@ -52,15 +41,13 @@ public function start($prompt, $historyFile) 'clear' ), true); - readline_completion_function($this->_getReadlineCompletionFunction($this->_vars)); + readline_completion_function([$this, 'readlineCompletionFunction']); // wait for the worker to finish executing hooks if (fread($this->_socket, 1) != EvalWorker::READY) { throw new \RuntimeException('EvalWorker failed to start'); } - $this->_readVars(); - $parser = new ShallowParser(); $buf = ''; $lineno = 1; @@ -89,7 +76,7 @@ public function start($prompt, $historyFile) $buf = ''; foreach ($statements as $stmt) { - if (false === $written = fwrite($this->_socket, $stmt)) { + if (false === $written = fwrite($this->_socket, EvalWorker::CMD_EVAL.$stmt)) { throw new \RuntimeException('Socket error: failed to write data'); } @@ -101,8 +88,6 @@ public function start($prompt, $historyFile) exit(0); } elseif ($status == EvalWorker::FAILED) { break; - } elseif($status == EvalWorker::DONE) { - $this->_readVars(); } } } @@ -119,118 +104,52 @@ public function clear() $this->_clear = true; } - private function _readVars() { - $vars = ""; - while(true) { - $tmp = fread($this->_socket, 1); - if($tmp === false || $tmp == "\n") { - break; - } - $vars .= $tmp; + public function readlineCompletionFunction() { + // Get the full input buffer so we can use some context when suggesting things. + $info = readline_info(); + $input = substr($info['line_buffer'], 0, $info['end']); + if (false === $written = fwrite($this->_socket, EvalWorker::CMD_COMPLETE.$input)) { + throw new \RuntimeException('Socket error: failed to write data'); } - $this->_vars = json_decode($vars, true); - } + $read = [$this->_socket]; + $write = null; + $except = [$this->_socket]; - private function _getReadlineCompletionFunction(&$local) { - return function() use (&$local) { - // Get the full input buffer so we can use some context when suggesting things. - $info = readline_info(); - $input = substr($info['line_buffer'], 0, $info['end']); - $return = array(); - // Accessing a class method or property - if(preg_match('/\$([a-zA-Z0-9_]+)\->[a-zA-Z0-9_]*$/', $input, $m)) { - $var = $m[1]; - $varValue = null; - - if(isset($local[EvalWorker::D_VARS][$var])) { - $varValue = $local[EvalWorker::D_VARS][$var]; + if(stream_select($read, $write, $except, 10) > 0 ) { + if($read) { + try { + stream_set_blocking($read[0], false); + $data = json_decode(stream_get_contents($read[0]), true); + } finally { + stream_set_blocking($read[0], true); } + return $data; + } + } - if($varValue !== null && $varValue[EvalWorker::D_VARS_TYPE] == 'object') { - $refl = new \ReflectionClass($varValue[EvalWorker::D_VARS_CLASS]); - $methods = $refl->getMethods(\ReflectionMethod::IS_PUBLIC); - foreach($methods as $method) { - $return[] = $method->name . '('; - } - $properties = $refl->getProperties(\ReflectionProperty::IS_PUBLIC); - foreach($properties as $property) { - $return[] = $property->name; - } - } - } // Are we trying to auto complete a static class method, constant or property? - else if(preg_match('/\$?([a-zA-Z0-9_\\\\]+)::(\$?)([a-zA-Z0-9_])*$/', $input, $m)) { - $class = $m[1]; - $refl = null; - - if(class_exists($class)) { - $refl = new \ReflectionClass($class); - } else if(isset($GLOBALS[$class]) && is_object($GLOBALS[$class])) { - $refl = new \ReflectionClass($GLOBALS[$class]); - } - if(!is_null($refl)) { - $exploded = explode('\\', $class); - $class = array_pop($exploded); - if(empty($m[2])) { - $methods = $refl->getMethods(\ReflectionMethod::IS_STATIC); - foreach($methods as $method) { - if($method->isPublic()) { - $return[] = $class . '::' . $method->name . '('; - } - } - $constants = $refl->getConstants(); - foreach($constants as $constant => $value) { - $return[] = $class . '::' . $constant; - } - $return[] = $class.'::class'; - } - if(!empty($m[2]) || empty($m[3])) { - $properties = $refl->getProperties(\ReflectionProperty::IS_STATIC); - foreach($properties as $property) { - if($property->isPublic()) { - $return[] = $class . '::$' . $property->name; - } - } - } - } - } else if(preg_match('/\\\\([a-zA-Z0-9_\\\\]+)$/', $input, $m)) { - $match = $m[1]; - $exploded = explode('\\', $match); - $lastComponentIndex = count($exploded) - 1; - if($lastComponentIndex == -1) { - return false; - } - $comp = []; - foreach(array_keys($this->_vars[EvalWorker::D_CLASSES]) as $cl) { - if(strncmp($match, $cl, strlen($match)) == 0) { - $clExploded = explode('\\', $cl); - array_splice($clExploded, 0, $lastComponentIndex); - $comp[implode('\\', $clExploded)] = true; - } - } + return ['']; - $return = array_keys($comp); + } - } else if(preg_match('/\'[^\']*$/', $input) || preg_match('/"[^"]*$/', $input)) { - return false; // This makes readline auto-complete files - } else if(preg_match('/\$[a-zA-Z0-9_]*$/', $input)) { - $return = array_keys($local[EvalWorker::D_VARS]); - } else { - $functions = $local[EvalWorker::D_FUNCTIONS]; - $classes = $local[EvalWorker::D_CLASSES]; - $functions['internal'] = array_map(function($v) { - return $v . '('; - }, $functions['internal']); + private function _read($socket) + { + $read = array( + $socket + ); + $except = array( + $socket + ); - $functions['user'] = array_map(function($v) { - return $v . '('; - }, $functions['user']); - $return = array_merge($return, $classes, $functions['user'], $functions['internal'], array('require ', 'echo ')); + if ($this->_select($read, $except) > 0) { + if ($read) { + $cmd = stream_get_contents($read[0], 1); + return [$cmd, stream_get_contents($read[0])]; + } else if ($except) { + throw new \UnexpectedValueException("Socket error: closed"); } - if(empty($return)) { - return array(''); - } - return $return; - }; + } + + return [null, null]; } } From 2fd041d9122e6af18141aa3738cbdc00f2235d40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20FRAN=C3=87OIS?= Date: Mon, 19 Dec 2016 11:12:35 +0100 Subject: [PATCH 3/4] cleanup --- lib/Boris/ReadlineClient.php | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/lib/Boris/ReadlineClient.php b/lib/Boris/ReadlineClient.php index b118add..a4a5829 100644 --- a/lib/Boris/ReadlineClient.php +++ b/lib/Boris/ReadlineClient.php @@ -131,25 +131,4 @@ public function readlineCompletionFunction() { return ['']; } - - private function _read($socket) - { - $read = array( - $socket - ); - $except = array( - $socket - ); - - if ($this->_select($read, $except) > 0) { - if ($read) { - $cmd = stream_get_contents($read[0], 1); - return [$cmd, stream_get_contents($read[0])]; - } else if ($except) { - throw new \UnexpectedValueException("Socket error: closed"); - } - } - - return [null, null]; - } } From 06623463537680dc810cb46c84788b93063630be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20FRAN=C3=87OIS?= Date: Mon, 19 Dec 2016 11:43:31 +0100 Subject: [PATCH 4/4] cleanup --- lib/Boris/EvalWorker.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/Boris/EvalWorker.php b/lib/Boris/EvalWorker.php index 54a753f..8f5dd5e 100644 --- a/lib/Boris/EvalWorker.php +++ b/lib/Boris/EvalWorker.php @@ -17,12 +17,6 @@ class EvalWorker const CMD_COMPLETE = "\1"; - const D_VARS = 'vars'; - const D_VARS_TYPE = 'type'; - const D_VARS_CLASS = 'class'; - const D_CLASSES = 'classes'; - const D_FUNCTIONS = 'functions'; - const INTERNAL_VARS = [ 'baseVars' => true, '__scope' => true,