RFC idea: Block scoped variables with "let $x = expr"
| From: | tyson andre | Date: | Sun, 15 Mar 2020 16:47:30 +0000 |
| Subject: | RFC idea: Block scoped variables with "let $x = expr" | ||
| Groups: | php.internals | ||
| Request: | Send a blank email to internals+get-109029@lists.php.net to get a copy of this message | ||
Hi internals,
In PHP, variables are currently scoped to the function scope, and can't be scoped to a block
scope. This makes it difficult to reason about how a variable will actually be used at a glance,
especially in long functions, or top-level statement lists of a file.
(or how the variable was originally intended to be used)
The function scope lifetime of variables in PHP is similar to how JavaScript treated variables with
var, before the introduction of the let statement in JS:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
Would there be any interest in adding something similar to this in PHP?
(Or have similar ideas been proposed in the past? I didn't see any.)
Correctness would be enforced as a best-effort at compile-time - the variables would continue to
only be freed at the end of the function call.
(e.g. __destruct() only gets called when the variable gets reassigned or the function call ends)
- Freeing it immediately would likely require the equivalent of a try{} finally{} to handle
exceptions.
try statements prevent opcache from optimizing a function, the last time I checked.
```
{
let $myObject = new MyClass(), $flag = true;
$myObject->process($flag);
}
// Accessing or setting $myObject or $flag outside a different let is an E_COMPILE_ERROR
// because it was declared anywhere else in the function body
// as a let statement
$myObject->doSomething();
// E_COMPILE_ERROR to access $key or $value after, outside of a separate let scope
foreach ($arr as let $key => let $value) {
// It would be a compile error to declare a gotoLabel: inside of a scope of a let statement.
}
// E_COMPILE_ERROR to access $key or $value after
echo $$var; // E_COMPILE_ERROR to use variable variables in the same scope, to enforce this as much
as possible.
{
let $outer = 1;
{
let $outer = 2; // E_COMPILE_ERROR to declare in a different scope, can only reassign
$outer = 3; // this is allowed
}
}
{
let $myRef =&$other;
}
{
let $myRef = true; // This removes myRef from the reference group before assigning a new value
to myRef - $other is unmodified.
}
```
I say "best-effort" because require() and $GLOBALS and get_defined_variables() can still
read or modify or make references to variables outside of a let,
depending on what's in the function body or top-level statements.
- Tyson