To allow for more strictness and type safety if a user wishes to have it, we need a way to make variable declarations explicit. When enabled, accessing an undeclared variable causes a compile-time error, regardless of whether the user is trying to read or write the variable. This RFC proposes a way to declare variables and to make the process optional for users.
Variables can be declared by using the var
keyword:
var $variable;
This initialises the variable with the value NULL
. It is equivalent to the following statement:
$variable = null;
Once a variable has been declared, redeclaring it triggers a compile-time error:
var $variable; var $variable; // Compile error: "Cannot redeclare variable $variable"
When declaring a variable, users may also initialise the variable:
var $variable = 'Initial Value';
Calling unset
on a variable removes the declared variable from the current scope:
var $variable; unset($variable); var_dump($variable); // Notice: Undefined variable $variable
With the new declare_vars
directive, the engine will throw a compile error when trying to access a variable that hasn't been declared:
declare(declare_vars=1); $variable = 'value'; // Compile error: "Undeclared variable: $variable" var_dump($otherVariable); // Compile error: "Undeclared variable: $otherVariable"
This is an alternative to the exception suggested in the Reclassifying engine warnings RFC when reading from an undefined variable. It further disallows implicitly declaring variables, allowing users to switch to this strict mode.
When variable declarations are required, variables can no longer be removed. Calling unset
leads to a compile time error:
declare(declare_vars=1); var $variable; unset($variable); // Compile error: Cannot unset declared variable
The declare(declare_vars=1)
statement must not use block mode. Doing so leads to a compile error:
declare(declare_vars=1) { }
Dynamic variables are evaluated at runtime. They can be declared and accessed as any other variables, but will throw an UndeclaredVariableError
when trying to access a dynamic variable that hasn't been declared. Redeclaring a dynamic variable leads to a RedeclaredVariableError
, while trying to unset a declared variable triggers an IllegalUnsetError
. These errors extend the Error
class.
declare(declare_vars=1); var $variableName = 'foo'; var $$variableName = 'value'; var_dump($$variableName); // 'value' var_dump($$$variableName); // UndeclaredVariableError: Undeclared variable $value var $$variableName; // RedeclaredVariableError: "Cannot redeclare variable $foo" unset($$variableName); // IllegalUnsetError: "Declared var $foo may not be unset"
The var
keyword has been chosen as it already exists, which avoids introducing another keyword to the language (e.g. let
). The var keyword is also necessary to differentiate explicit from implicit declarations. Most importantly, the var
keyword is necessary since a possible future introduction of typed variables could create an ambiguity in the parser:
require $file;
This could either be a require
statement that requires the file stored in $file
, or a variable declaration for $file
of type require
(which is a valid class name in PHP 7). Using a keyword to mark a variable declaration removes this ambiguity.
No BC breaks are introduced by this RFC. The declare_vars
directive is optional to prevent breaking existing implicit variable declarations or accessing undefined variables.
PHP 8.0
None
Thie RFC will be followed by a number of other RFCs to expand the functionality of explicit declarations. These are not part of the RFC; please limit discussion to the scope of this RFC.
In the future, variable declarations may optionally add a type to the variable:
var ?string $string; var ?int = null; var My\Object = new My\Object();
A future RFC could introduce lexical scopes, allowing to better control where variables can be accessed:
var $unscopedVariable; { var $scopedVariable; } var_dump($unscopedVariable); // NULL var_dump($scopedVariable); // Compile error: "Undeclared variable $scopedVariable"
The variable declaration logic could also be applied to class properties, which would disallow dynamic properties. This is part of a separate RFC and will use a separate declare
switch, as users may want to enforce declaration of variables in code that should also dynamic properties for their class.
A future RFC may add support for constant variables, which can't be reassigned:
const $foo = 'value'; $foo = 'other value'; // Compile error: "Can't assign value to constant variable $foo"
A yes/no vote.
A prototype implementation is available at https://github.com/sgolemon/php-src/tree/sgolemon.declared-vars (work in progress)
After the project is implemented, this section should contain
Links to external references, discussions or RFCs
Keep this updated with features that were discussed on the mail lists.