diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index ebaa07ecd5..86c552e8d5 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -462,13 +462,7 @@ class Process */ public function getOutput() { - if ($this->outputDisabled) { - throw new LogicException('Output has been disabled.'); - } - - $this->requireProcessIsStarted(__FUNCTION__); - - $this->readPipes(false, '\\' === DIRECTORY_SEPARATOR ? !$this->processInformation['running'] : true); + $this->readPipesForOutput(__FUNCTION__); if (false === $ret = stream_get_contents($this->stdout, -1, 0)) { return ''; @@ -490,11 +484,7 @@ class Process */ public function getIncrementalOutput() { - if ($this->outputDisabled) { - throw new LogicException('Output has been disabled.'); - } - - $this->requireProcessIsStarted(__FUNCTION__); + $this->readPipesForOutput(__FUNCTION__); $latest = stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset); $this->incrementalOutputOffset = ftell($this->stdout); @@ -530,13 +520,7 @@ class Process */ public function getErrorOutput() { - if ($this->outputDisabled) { - throw new LogicException('Output has been disabled.'); - } - - $this->requireProcessIsStarted(__FUNCTION__); - - $this->readPipes(false, '\\' === DIRECTORY_SEPARATOR ? !$this->processInformation['running'] : true); + $this->readPipesForOutput(__FUNCTION__); if (false === $ret = stream_get_contents($this->stderr, -1, 0)) { return ''; @@ -559,11 +543,7 @@ class Process */ public function getIncrementalErrorOutput() { - if ($this->outputDisabled) { - throw new LogicException('Output has been disabled.'); - } - - $this->requireProcessIsStarted(__FUNCTION__); + $this->readPipesForOutput(__FUNCTION__); $latest = stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset); $this->incrementalErrorOutputOffset = ftell($this->stderr); @@ -1328,6 +1308,24 @@ class Process return self::$sigchild = false !== strpos(ob_get_clean(), '--enable-sigchild'); } + /** + * Reads pipes for the freshest output. + * + * @param $caller The name of the method that needs fresh outputs + * + * @throw LogicException in case output has been disabled or process is not started + */ + private function readPipesForOutput($caller) + { + if ($this->outputDisabled) { + throw new LogicException('Output has been disabled.'); + } + + $this->requireProcessIsStarted($caller); + + $this->updateStatus(false); + } + /** * Validates and returns the filtered timeout. * diff --git a/src/Symfony/Component/Process/Tests/ProcessTest.php b/src/Symfony/Component/Process/Tests/ProcessTest.php index 9d6a607830..d1496236a3 100644 --- a/src/Symfony/Component/Process/Tests/ProcessTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessTest.php @@ -1159,6 +1159,31 @@ class ProcessTest extends \PHPUnit_Framework_TestCase return $codes; } + /** + * @dataProvider provideVariousIncrementals + */ + public function testIncrementalOutputDoesNotRequireAnotherCall($stream, $method) { + $process = new Process(self::$phpBin.' -r '.escapeshellarg('$n = 0; while ($n < 3) { file_put_contents(\''.$stream.'\', $n, 1); $n++; usleep(1000); }'), null, null, null, null); + $process->start(); + $result = ''; + $limit = microtime(true) + 3; + $expected = '012'; + + while ($result !== $expected && microtime(true) < $limit) { + $result .= $process->$method(); + } + + $this->assertSame($expected, $result); + $process->stop(); + } + + public function provideVariousIncrementals() { + return array( + array('php://stdout', 'getIncrementalOutput'), + array('php://stderr', 'getIncrementalErrorOutput'), + ); + } + /** * provides default method names for simple getter/setter. */