diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index 32704df3f1..11ee3a9385 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -463,13 +463,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 ''; @@ -491,11 +485,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); @@ -531,13 +521,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 ''; @@ -560,11 +544,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 652246267c..e06cb994c4 100644 --- a/src/Symfony/Component/Process/Tests/ProcessTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessTest.php @@ -1165,6 +1165,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. */