public function __construct($name, $pid, Error $error = null) { $this->name = $name; $this->pid = $pid; $this->error = $error; if ($error) { if (__CLASS__ === $error->getClass()) { parent::__construct(sprintf('%s via "%s" fork (%d)', $error->getMessage(), $name, $pid)); } else { parent::__construct(sprintf('%s (%d) thrown in "%s" fork (%d): "%s" (%s:%d)', $error->getClass(), $error->getCode(), $name, $pid, $error->getMessage(), $error->getFile(), $error->getLine())); } } else { parent::__construct(sprintf('An unknown error occurred in "%s" fork (%d)', $name, $pid)); } }
/** * Forks something into another process and returns a deferred object. */ public function fork($callable) { if (!is_callable($callable)) { throw new UnexpectedTypeException($callable, 'callable'); } // allow the system to cleanup before forking $this->dispatcher->dispatch(Events::PRE_FORK); if (-1 === ($pid = pcntl_fork())) { throw new ProcessControlException('Unable to fork a new process'); } if (0 === $pid) { // reset the list of child processes $this->forks = array(); // setup the fifo (blocks until parent connects) $fifo = new Fifo(null, $this->signal); $message = new ExitMessage(); // phone home on shutdown register_shutdown_function(function () use(&$fifo, &$message) { $status = null; try { $fifo->send($message, false); } catch (\Exception $e) { // probably an error serializing the result $message->setResult(null); $message->setError(Error::fromException($e)); $fifo->send($message, false); exit(2); } }); // dispatch an event so the system knows it's in a new process $this->dispatcher->dispatch(Events::POST_FORK); if (!$this->debug) { ob_start(); } try { $result = call_user_func($callable, $fifo); $message->setResult($result); $status = is_integer($result) ? $result : 0; } catch (\Exception $e) { $message->setError(Error::fromException($e)); $status = 1; } if (!$this->debug) { $message->setOutput(ob_get_clean()); } exit($status); } // connect to the fifo $fifo = new Fifo($pid); return $this->forks[$pid] = new Fork($pid, $fifo, $this->debug); }