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