1*04fd306cSNickeau<?php 2*04fd306cSNickeau 3*04fd306cSNickeau/* 4*04fd306cSNickeau * This file is part of the Symfony package. 5*04fd306cSNickeau * 6*04fd306cSNickeau * (c) Fabien Potencier <fabien@symfony.com> 7*04fd306cSNickeau * 8*04fd306cSNickeau * For the full copyright and license information, please view the LICENSE 9*04fd306cSNickeau * file that was distributed with this source code. 10*04fd306cSNickeau */ 11*04fd306cSNickeau 12*04fd306cSNickeaunamespace Symfony\Component\Process; 13*04fd306cSNickeau 14*04fd306cSNickeauuse Symfony\Component\Process\Exception\RuntimeException; 15*04fd306cSNickeau 16*04fd306cSNickeau/** 17*04fd306cSNickeau * Provides a way to continuously write to the input of a Process until the InputStream is closed. 18*04fd306cSNickeau * 19*04fd306cSNickeau * @author Nicolas Grekas <p@tchwork.com> 20*04fd306cSNickeau * 21*04fd306cSNickeau * @implements \IteratorAggregate<int, string> 22*04fd306cSNickeau */ 23*04fd306cSNickeauclass InputStream implements \IteratorAggregate 24*04fd306cSNickeau{ 25*04fd306cSNickeau /** @var callable|null */ 26*04fd306cSNickeau private $onEmpty = null; 27*04fd306cSNickeau private $input = []; 28*04fd306cSNickeau private $open = true; 29*04fd306cSNickeau 30*04fd306cSNickeau /** 31*04fd306cSNickeau * Sets a callback that is called when the write buffer becomes empty. 32*04fd306cSNickeau */ 33*04fd306cSNickeau public function onEmpty(callable $onEmpty = null) 34*04fd306cSNickeau { 35*04fd306cSNickeau $this->onEmpty = $onEmpty; 36*04fd306cSNickeau } 37*04fd306cSNickeau 38*04fd306cSNickeau /** 39*04fd306cSNickeau * Appends an input to the write buffer. 40*04fd306cSNickeau * 41*04fd306cSNickeau * @param resource|string|int|float|bool|\Traversable|null $input The input to append as scalar, 42*04fd306cSNickeau * stream resource or \Traversable 43*04fd306cSNickeau */ 44*04fd306cSNickeau public function write($input) 45*04fd306cSNickeau { 46*04fd306cSNickeau if (null === $input) { 47*04fd306cSNickeau return; 48*04fd306cSNickeau } 49*04fd306cSNickeau if ($this->isClosed()) { 50*04fd306cSNickeau throw new RuntimeException(sprintf('"%s" is closed.', static::class)); 51*04fd306cSNickeau } 52*04fd306cSNickeau $this->input[] = ProcessUtils::validateInput(__METHOD__, $input); 53*04fd306cSNickeau } 54*04fd306cSNickeau 55*04fd306cSNickeau /** 56*04fd306cSNickeau * Closes the write buffer. 57*04fd306cSNickeau */ 58*04fd306cSNickeau public function close() 59*04fd306cSNickeau { 60*04fd306cSNickeau $this->open = false; 61*04fd306cSNickeau } 62*04fd306cSNickeau 63*04fd306cSNickeau /** 64*04fd306cSNickeau * Tells whether the write buffer is closed or not. 65*04fd306cSNickeau */ 66*04fd306cSNickeau public function isClosed() 67*04fd306cSNickeau { 68*04fd306cSNickeau return !$this->open; 69*04fd306cSNickeau } 70*04fd306cSNickeau 71*04fd306cSNickeau /** 72*04fd306cSNickeau * @return \Traversable<int, string> 73*04fd306cSNickeau */ 74*04fd306cSNickeau #[\ReturnTypeWillChange] 75*04fd306cSNickeau public function getIterator() 76*04fd306cSNickeau { 77*04fd306cSNickeau $this->open = true; 78*04fd306cSNickeau 79*04fd306cSNickeau while ($this->open || $this->input) { 80*04fd306cSNickeau if (!$this->input) { 81*04fd306cSNickeau yield ''; 82*04fd306cSNickeau continue; 83*04fd306cSNickeau } 84*04fd306cSNickeau $current = array_shift($this->input); 85*04fd306cSNickeau 86*04fd306cSNickeau if ($current instanceof \Iterator) { 87*04fd306cSNickeau yield from $current; 88*04fd306cSNickeau } else { 89*04fd306cSNickeau yield $current; 90*04fd306cSNickeau } 91*04fd306cSNickeau if (!$this->input && $this->open && null !== $onEmpty = $this->onEmpty) { 92*04fd306cSNickeau $this->write($onEmpty($this)); 93*04fd306cSNickeau } 94*04fd306cSNickeau } 95*04fd306cSNickeau } 96*04fd306cSNickeau} 97