PHP RFC: Variable declarations before usage
- Version: 0.1
- Date: 2019-09-19
- Authors: Sara Golemon, pollita@php.net; Andreas Braun, alcaeus@php.net
- Status: Draft
- First Published at: http://wiki.php.net/rfc/declare_vars
Introduction
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.
Proposal
Declaring variables
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
Requiring variables to be declared before accessing them
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
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"
Why use a keyword for variable declarations?
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.
Backward Incompatible Changes
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.
Proposed PHP Version(s)
PHP 8.0
Open Issues
None
Future Scope
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.
Typed variables
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();
Lexical scopes
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"
Disallow dynamic object properties
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.
Constant variables
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"
Proposed Voting Choices
A yes/no vote.
Patches and Tests
A prototype implementation is available at https://github.com/sgolemon/php-src/tree/sgolemon.declared-vars (work in progress)
Implementation
After the project is implemented, this section should contain
- the version(s) it was merged into
- a link to the git commit(s)
- a link to the PHP manual entry for the feature
- a link to the language specification section (if any)
References
Links to external references, discussions or RFCs
Rejected Features
Keep this updated with features that were discussed on the mail lists.