InputStream.php 2.3 KB

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