/** * 創建所需的 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]每天TP5-20170126|thinkphp5-Process.php-8
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.