/** * 创建所需的 proc_open 的描述符 * @return array */ private function getDescriptors() {// 获取描述符 if (‘\\‘ === DS) {// 如果是windows $this->processPipes = WindowsPipes::create($this, $this->input);// 创建 windows 管道系统 } else { $this->processPipes = UnixPipes::create($this, $this->input);// 创建 unix 管道系统 } $descriptors = $this->processPipes->getDescriptors($this->outputDisabled);// 获取描述信息 if (!$this->useFileHandles && $this->enhanceSigchildCompatibility && $this->isSigchildEnabled()) { $descriptors = array_merge($descriptors, [[‘pipe‘, ‘w‘]]);// 如果满足上述 的全部条件 $this->commandline = ‘(‘ . $this->commandline . ‘) 3>/dev/null; code=$?; echo $code >&3; exit $code‘; }// 进行 命令行设置 return $descriptors;// 返回描述,并且 执行 命令行工具 } /** * 建立 wait () 使用的回调。 * @param callable|null $callback * @return callable */ protected function buildCallback($callback) {// wait 使用回调 建立 回调函数 $out = self::OUT;// 输出 $callback = function ($type, $data) use ($callback, $out) {// 回调函数 // 闭包 用法 // 很经典的一个用法 if ($out == $type) {// 如果 可以输出 $this->addOutput($data); } else {// 否则添加错误数据 $this->addErrorOutput($data); } if (null !== $callback) {// 回调 call_user_func($callback, $type, $data); } }; return $callback;// 返回一个回调函数 } /** * 更新状态 * @param bool $blocking */ protected function updateStatus($blocking) {// 更新状态 if (self::STATUS_STARTED !== $this->status) {// 当前状态不是启动状态 工作状态 return; }// 如果状态不对,直接返回 $this->processInformation = proc_get_status($this->process);// 获取进程状态信息 $this->captureExitCode();// 获取执行代码 $this->readPipes($blocking, ‘\\‘ === DS ? !$this->processInformation[‘running‘] : true);// 读取管道信息 if (!$this->processInformation[‘running‘]) {//如果当前信息 没有运行中 $this->close();// 关闭 } }// 在经历了3次外包之后,基本上就 没有 那个东西了是可以被看见的了 /** * 是否开启 ‘--enable-sigchild‘ * @return bool */ protected function isSigchildEnabled() { if (null !== self::$sigchild) {// 返回默认状态 return self::$sigchild; } if (!function_exists(‘phpinfo‘)) {// 如果没有 phpinfo 这个函数 return self::$sigchild = false; } ob_start();// 开启缓存 phpinfo(INFO_GENERAL);// 信息 启动 return self::$sigchild = false !== strpos(ob_get_clean(), ‘--enable-sigchild‘);// 很神奇的判断方式 } /** * 验证是否超时 * @param int|float|null $timeout * @return float|null */ private function validateTimeout($timeout) {// 验证是否超时 $timeout = (float)$timeout;// 设置时间 if (0.0 === $timeout) {// 如果 为0 $timeout = null;// 时间为空 } elseif ($timeout < 0) {// 如果时间 小于0 异常 throw new \InvalidArgumentException(‘The timeout value must be a valid positive integer or float number.‘); } return $timeout; } /** * 读取pipes * @param bool $blocking * @param bool $close */ private function readPipes($blocking, $close) { $result = $this->processPipes->readAndWrite($blocking, $close);// 读写数据 $callback = $this->callback;// 回调 foreach ($result as $type => $data) {// 对返回数据进行 处理 if (3 == $type) {// 数据类型,返回错误代码 $this->fallbackExitcode = (int)$data; } else { $callback($type === self::STDOUT ? self::OUT : self::ERR, $data); } } } /** * 捕获退出码 */ private function captureExitCode() {// 捕获退出码 if (isset($this->processInformation[‘exitcode‘]) && -1 != $this->processInformation[‘exitcode‘]) { $this->exitcode = $this->processInformation[‘exitcode‘]; } }// 将系统运行命令的退出码,放到系统配置项里面 /** * 关闭资源 * @return int 退出码 */ private function close() {// 执行 资源 关闭 $this->processPipes->close();// 关闭资源 if (is_resource($this->process)) {// 是否有资源 $exitcode = proc_close($this->process);// 执行进程关闭函数 } else { $exitcode = -1;// 否则 退出码为1 } $this->exitcode = -1 !== $exitcode ? $exitcode : (null !== $this->exitcode ? $this->exitcode : -1); $this->status = self::STATUS_TERMINATED; // 退出码 // 当前状态 if (-1 === $this->exitcode && null !== $this->fallbackExitcode) { $this->exitcode = $this->fallbackExitcode; } elseif (-1 === $this->exitcode && $this->processInformation[‘signaled‘] && 0 < $this->processInformation[‘termsig‘] ) { $this->exitcode = 128 + $this->processInformation[‘termsig‘]; }// 是否正常终止,还是异常中断 return $this->exitcode;// 返回退出码 } /** * 重置数据 */ private function resetProcessData() {// 重置全部数据 $this->starttime = null; $this->callback = null; $this->exitcode = null; $this->fallbackExitcode = null; $this->processInformation = null; $this->stdout = null; $this->stderr = null; $this->process = null; $this->latestSignal = null; $this->status = self::STATUS_READY; $this->incrementalOutputOffset = 0; $this->incrementalErrorOutputOffset = 0; } /** * 将一个 POSIX 信号发送到进程中。 * @param int $signal * @param bool $throwException * @return bool */ private function doSignal($signal, $throwException) {// 信号发送到进程中 if (!$this->isRunning()) { if ($throwException) {// 抛出异常 throw new \LogicException(‘Can not send signal on a non running process.‘); } return false; } if ($this->isSigchildEnabled()) { if ($throwException) { throw new \RuntimeException(‘This PHP has been compiled with --enable-sigchild. The process can not be signaled.‘); }// 是否 子进程 return false; } if (true !== @proc_terminate($this->process, $signal)) { if ($throwException) { throw new \RuntimeException(sprintf(‘Error while sending signal `%s`.‘, $signal)); }// 进程 中断 return false; } $this->latestSignal = $signal; // 最终 信号 return true;// 返回值 } /** * 确保进程已经开启 * @param string $functionName */ private function requireProcessIsStarted($functionName) {// 确认进程开启 if (!$this->isStarted()) { throw new \LogicException(sprintf(‘Process must be started before calling %s.‘, $functionName)); } } /** * 确保进程已经终止 * @param string $functionName */ private function requireProcessIsTerminated($functionName) {// 确认进程关闭 if (!$this->isTerminated()) { throw new \LogicException(sprintf(‘Process must be terminated before calling %s.‘, $functionName)); } } }
本文出自 “专注php 群号:414194301” 博客,请务必保留此出处http://jingshanls.blog.51cto.com/3357095/1887146
[李景山php]每天TP5-20170126|thinkphp5-Process.php-8
原文:http://jingshanls.blog.51cto.com/3357095/1887146