InputStream.php 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  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($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. /**
  63. * @return \Traversable<int, string>
  64. */
  65. #[\ReturnTypeWillChange]
  66. public function getIterator()
  67. {
  68. $this->open = true;
  69. while ($this->open || $this->input) {
  70. if (!$this->input) {
  71. yield '';
  72. continue;
  73. }
  74. $current = array_shift($this->input);
  75. if ($current instanceof \Iterator) {
  76. yield from $current;
  77. } else {
  78. yield $current;
  79. }
  80. if (!$this->input && $this->open && null !== $onEmpty = $this->onEmpty) {
  81. $this->write($onEmpty($this));
  82. }
  83. }
  84. }
  85. }