# BoundedScope I tried to refine the `BoundedScope` class to its logical completeness, considering your feedback. However, I no longer like it because it now resembles an advanced `ComposeFuture` or `BoundedFuture` (I'm not even sure which one).
There is no doubt that such functionality is needed, but I have concerns about the design. It seems better to implement `BoundedFuture` separately (placing it in a dedicated RFC) and incorporate this logic there, while `BoundedScope` might not be necessary at all. Essentially, the code using `BoundedScope` could be replaced with: ```php $scope = new Scope(); $future = BoundedFuture(); try { await $future; } finally { $scope->dispose(); } ``` On the other hand, a method like `spawnAndProlong` could be useful if there is a need to implement a pattern where the `Scope` remains alive as long as at least one task is active. But is this case significant enough to keep it? I'm not sure. I need some time to process this. In the meantime, I'll show you the draft I came up with. #### BoundedScope The `BoundedScope` class is designed to create explicit constraints that will be applied to all coroutines spawned within the specified Scope. The `BoundedScope` class implements the following pattern: ```php $scope = new Scope(); $constraints = new Future(); $scope->spawn(function () use($constraints) { try { await $constraints; } finally { \Async\currentScope()->cancel(); } }); ``` Here, `$constraints` is an object implementing the `Awaitable` interface. Once it completes, the `Scope` will be terminated, and all associated resources will be released. | Method | Description | |----------------------------------------|-------------------------------------------------------------------------------------------------------------| | `defineTimeout(int $milliseconds)` | Define a specified timeout, automatically canceling coroutines when the time expires. | | `spawnAndBound(callable $coroutine)` | Spawns a coroutine and restricts the lifetime of the entire Scope to match the coroutine’s lifetime. | | `spawnAndProlong(callable $coroutine)` | Spawns a coroutine and extends the lifetime of the entire Scope to match the coroutine’s lifetime. | | `boundedBy(Awaitable $constraint)` | Limits the scope’s lifetime based on a **Cancellation token, Future, or another coroutine's lifetime**. | | `prolongedBy(Awaitable $constraint)` | Extends the scope’s lifetime based on a **Cancellation token, Future, or another coroutine's lifetime**. | ```php $scope = new BoundedScope(); $scope->defineTimeout(1000); $scope->spawnAndBound(function() { sleep(2); echo "Task 1\n"; }); await $scope; ``` ##### Prolong and Bound triggers The `BoundedScope` class operates with two types of triggers: - **Bound trigger** – limits execution time by the minimum boundary. - **Prolong trigger** – limits execution time by the maximum boundary. For the **Prolong** trigger to execute, all **Prolong** objects must be completed. For the **Bound** trigger to execute, at least one **Bound** object must be completed. The `Scope` will terminate as soon as either the **Prolong** or **Bound** trigger is executed. ##### defineTimeout The `defineTimeout` method sets a global timeout for all coroutines belonging to a `Scope`. The method initializes a single internal timer, which starts when `defineTimeout` is called. When the timer expires, the `Scope::cancel()` method is invoked. The `defineTimeout` method can only be called once; a repeated call will throw an exception. ##### spawnAndBound / spawnAndProlong `spawnAndBound` creates a coroutine and limits its execution time to the current `Scope`. The method can be called multiple times. In this case, the `Scope` will not exist longer than the lifetime of the shortest coroutine. `spawnAndProlong` creates a coroutine and extends the lifetime of the current `Scope` to match the coroutine's lifetime. ##### boundedBy / prolongedBy The `boundedBy` method allows limiting the lifetime of a `Scope` by explicitly specifying an object that implements the `Awaitable` interface. The `Awaitable` interface is inherited by classes such as `Coroutine` and `Scope`. Additionally, classes like `Future` and `Cancellation`, which are not part of this RFC, can also implement the `Awaitable` interface.