# 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.