On 13/06/2022 13:29, Arnaud Le Blanc wrote:
Following your comment, I have clarified a few things in the "Auto-capture
semantics" section. This includes a list of way in which these effects can be
observed. These are really marginal cases that are not relevant for most
programs.


I'm not sure I agree that all of these are marginal, or with the way you've characterised them...


> Note that destructor timing is undefined in PHP, especially when reference cycles exist.

Outside of reference cycles, which are pretty rare and generally easy to avoid, PHP's destructors are entirely deterministic. Unlike in fully garbage-collected languages, you can use a plain object to implement an "RAII" pattern - e.g. the constructor locks a file and the destructor unlocks it; or the constructor starts a transaction, and the destructor rolls it back if not yet committed.

A related case is resource lifetime: file and network handles are guaranteed to be closed when they go out of scope, and accidentally taking an extra copy of their "value" can prevent that.


> It ends up capturing the same variables that would have been captured by a manually curated |use| list.

This slightly muddles two different questions:

1) Given a well-written closure, where all variables are either clearly local or clearly intended to be captured, does the implementation do a good job of distinguishing them? 2) Given a badly-written closure, where variables are accidentally ambiguous, what side-effects might the user experience?

The answer to question 1 seems to be yes, the implementation does a good job, and that's good news, and thank you for working on it.

That is not the same, however, as saying that question 2 is never relevant. Consider the following, adapted from an example in the RFC:

$filter = fn ($user) {
    if ( $user->id !== -1 ) {
        $guest = $repository->findByUserId($user->id);
    }
    return isset($guest) && in_array($guest->id, $guestsIds);
};

This is not particularly great code, but it works ... unless the parent scope happens to have a variable named $guest, which will then be bound to the closure, since there is a path where it is read before being written. In this case, side effects include:

* The behaviour will change based on the captured value of $guest
* Any resources held by that value will be held until $filter is destructed, rather than when $guest is destructed


Whether the risk of these side effects is a big problem is up for debate, but it's wrong to suggest they don't exist.


Regards,

--
Rowan Tommins
[IMSoP]

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php

Reply via email to