RFC idea: Block scoped variables with "let $x = expr"

From: 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

« previous php.internals (#109029) next »