Re: PHP True Async RFC - Stage 2

From: Date: Mon, 17 Mar 2025 11:02:14 +0000
Subject: Re: PHP True Async RFC - Stage 2
References: 1 2  Groups: php.internals 
Request: Send a blank email to [email protected] to get a copy of this message
# 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.


Thread (59 messages)

« previous php.internals (#126802) next »