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