rfc:closure_self_reference

This is an old revision of the document!


PHP RFC: Closure self reference

Introduction

Currently, the main way used to call a closure from within that closure, is to bind a variable by reference into the closure, when the closure is created.

However this can lead to shenanigans:

$fibonacci = function (int $n) use (&$fibonacci) {
    if ($n === 0) return 0;
    if ($n === 1) return 1;
    return $fibonacci($n-1) + $fibonacci($n-2);
};
 
echo $fibonacci(10). "\n";
$this_is_the_original_fibonacci = $fibonacci;
// ... many lines of code here
$fibonacci = function (int $n) { return rand(0, $n); };
// ... many lines of code here
 
echo $this_is_the_original_fibonacci(10). "\n";

i.e. a change to the variable outside the closure has modified the behaviour of the closure. That a closure can change behaviour like this violates the Principle of least astonishment

Proposal

Similar to how $this is defined automatically inside closures that are defined inside classes, add a $lambda variable to all closures, that references the current closure.

A closure that needs to call itself can now use the $lambda variable, instead of having to pass in a variable by reference:

$fibonacci = function (int $n) {
    if ($n === 0) return 0;
    if ($n === 1) return 1;
    return $lambda($n-1) + $lambda($n-2);
};

Any use of $lambda outside of a closure would give an error, similar to how using $this outside of a method of a class instance is not allowed.

function foo() {
   $lambda();
}
foo();
// Fatal error: Using $lambda when not in closure context in %s

BC concerns

Although this proposal wouldn't require a large amount of change to existing code, people might not be aware that the use $lambda anywhere in their code.

Because of this it probably makes sense to break the change into two steps:

  • In one release emit a deprecation notice for any use of a variable named 'lambda'.
  • In the next release add the ability to use $lambda inside a closure, with the meaning of 'the current closure'.

Why the name '$lambda' ?

Seems a reasonable choice as:

  • People who don't know what a lambda is are unlikely to use that name by accident.
  • People who do know what a lambda is are likely to be able to remember it.
  • I find it a a fun word to say.
$closure = function () { echo "Hello.";};
// Fatal error: Using $closure when not in closure context in %s
// Whoever wrote this code is likely to be confused.
$lambda = function () { echo "Hello.";};
// Fatal error: Using $lambda when not in closure context in %s
// Whoever wrote this code has a reasonable chance of understanding the issue.

Backward Incompatible Changes

Use of any variable named $lambda would issue a deprecation notice on the version where a deprecation notice is added.

Any use of $lambda would have to be inside a closure for versions after it is added.

Proposed PHP Versions

The voting choices will allow people to choose between:

Either: Deprecate use of $lambda in 8.1 and introduce $lambda to be available inside closures for 8.2

Or: Deprecate use of $lambda in the last planned minor release of PHP 8 and introduce $lambda to be available inside closures for PHP 9.0

or rejecting the RFC.

RFC Impact

To Opcache

Unknown.

Future Scope

Why not make $lambda usable in all functions, and just refer to the current function/method

Probably better to just error...unless someone can think of good reasons either way. TBH, I'd probably prefer it to error, to prevent accidental usage.

Proposed Voting Choices

Vote 1

  • Accept this RFC, give a deprecation notice for any use of a variable called 'lambda' in PHP 8.1 and support the $lambda variable inside any closure from PHP 8.2
  • Reject this RFC.

Vote 2

  • Accept this RFC, but at versions PHP 8.x (where x is the last planned minor version for PHP 8) for deprecation and adding $lambda to PHP 9.0.
  • Reject this RFC.

If the result of 'vote 1' is to accept the RFC, then vote 2 is moot.

Patches and Tests

Links to any external patches and tests go here.

Implementation

None yet.

References

Links to external references, discussions or RFCs

Rejected Features

Keep this updated with features that were discussed on the mail lists.

rfc/closure_self_reference.1605042728.txt.gz · Last modified: 2020/11/10 21:12 by crell