1<?php 2 3declare(strict_types=1); 4 5namespace GuzzleHttp\Promise; 6 7/** 8 * A task queue that executes tasks in a FIFO order. 9 * 10 * This task queue class is used to settle promises asynchronously and 11 * maintains a constant stack size. You can use the task queue asynchronously 12 * by calling the `run()` function of the global task queue in an event loop. 13 * 14 * GuzzleHttp\Promise\Utils::queue()->run(); 15 * 16 * @final 17 */ 18class TaskQueue implements TaskQueueInterface 19{ 20 private $enableShutdown = true; 21 private $queue = []; 22 23 public function __construct(bool $withShutdown = true) 24 { 25 if ($withShutdown) { 26 register_shutdown_function(function (): void { 27 if ($this->enableShutdown) { 28 // Only run the tasks if an E_ERROR didn't occur. 29 $err = error_get_last(); 30 if (!$err || ($err['type'] ^ E_ERROR)) { 31 $this->run(); 32 } 33 } 34 }); 35 } 36 } 37 38 public function isEmpty(): bool 39 { 40 return !$this->queue; 41 } 42 43 public function add(callable $task): void 44 { 45 $this->queue[] = $task; 46 } 47 48 public function run(): void 49 { 50 while ($task = array_shift($this->queue)) { 51 /** @var callable $task */ 52 $task(); 53 } 54 } 55 56 /** 57 * The task queue will be run and exhausted by default when the process 58 * exits IFF the exit is not the result of a PHP E_ERROR error. 59 * 60 * You can disable running the automatic shutdown of the queue by calling 61 * this function. If you disable the task queue shutdown process, then you 62 * MUST either run the task queue (as a result of running your event loop 63 * or manually using the run() method) or wait on each outstanding promise. 64 * 65 * Note: This shutdown will occur before any destructors are triggered. 66 */ 67 public function disableShutdown(): void 68 { 69 $this->enableShutdown = false; 70 } 71} 72