rfc:calls_in_constant_expressions_poll

Poll: Places to allow function calls in constant expressions

Introduction

Right now, various statement types don't allow function calls, even in places where it is feasible for the language to support, or may be useful to do so. Instead, the values are limited to constant expressions (this poll defines “constant expressions” as the allowed types of expressions (constants, certain operators, literals, etc., in the current php implementation).

  1. Initial values of static or instance properties. This poll only addresses static properties.
  2. Parameter defaults of functions, methods, and closures.
  3. Class constant values.
  4. Global constant values.
  5. Static variable default values.

This poll was created to gather opinions on which of the above statement types would be desirable to change, and in which ways, to shape subsequent RFCs. It seems desirable to change some of these expression types (e.g. parameter defaults, static properties) in different ways from others.

Proposal

The RFC https://wiki.php.net/rfc/calls_in_constant_expressions proposed to allow function calls in all of the above expression types, as long as that function returned a constant. It was later changed to support only a whitelist of function calls.

Because of the following list of reasons, that RFC is being put on hold to gather feedback before rewriting it.

  • That RFC would affect those 5 use cases the same way. Although the restriction to constant expressions is currently the same for those 5 use cases, there's no technical reason to force them to continue to be the same in the future.
  • It would be useful to allow any function calls (even those returning objects or references) in parameter defaults and static property defaults (e.g. methods, functions returning objects, .). (Parameter defaults containing function calls would behave as if they were evaluated every time the function was called without that parameter)
  • Preferring to make a choice on whether or not the RFC uses a whitelist before the vote is started.

Implementation Details

For parameter defaults, the proposed behavior would be that default expressions containing calls would get evaluated every time the parameter default was used. Opcache would be free to optimize deterministic functions known to have no side effects at compile time (e.g. $x = strlen(self::NAME) could become a constant, but the value of $x = generate_unique_id() would change.). Functions would behave as if they were evaluated in a closure with an empty parameter list variable scope. Using variables or known functions accessing the variable scope (func_get_args(), get_defined_variables(), extract(), etc.) would cause a parse/compile error.

  • The closure is likely needed for array_map('self::my_method', ARGS) to work as expected in the PHP engine, due to the way the php engine resolves self and strict_types of the callee. If it turns out to be unnecessary, it won't be used.
  • The variable scope a class/function was declared in is temporary, which is why access to it is forbidden.

The planned strict_types behavior is to use the strict_types setting of the file containing the constant expression.

Vote

The evaluation order and error handling would be as described in https://wiki.php.net/rfc/calls_in_constant_expressions , except where noted otherwise.

Future RFCs will only enforce that the final result is allowed as a constant for class/global constants. (e.g. const X = [“constant value”, any_function_call()][0] will not throw an error about being an invalid constant even if any_function_call() contains objects or references, because the final result is the string “constant value”)

Voting ends March 4th, 2020.

Support calls in class constants
Real name No Whitelist of global functions Any function or method call
bishop (bishop)   
bwoebi (bwoebi)   
carusogabriel (carusogabriel)   
colinodell (colinodell)   
derick (derick)   
dmitry (dmitry)   
galvao (galvao)   
ircmaxell (ircmaxell)   
jbnahan (jbnahan)   
kalle (kalle)   
malukenho (malukenho)   
marandall (marandall)   
ocramius (ocramius)   
pierrick (pierrick)   
pollita (pollita)   
rasmus (rasmus)   
salathe (salathe)   
sergey (sergey)   
stas (stas)   
svpernova09 (svpernova09)   
zimt (zimt)   
Final result: 14 5 2
This poll has been closed.

.

Support calls in global constants
Real name No Whitelist of global functions Any function or method call
bishop (bishop)   
carusogabriel (carusogabriel)   
dmitry (dmitry)   
galvao (galvao)   
ircmaxell (ircmaxell)   
jbnahan (jbnahan)   
kalle (kalle)   
malukenho (malukenho)   
marandall (marandall)   
ocramius (ocramius)   
pierrick (pierrick)   
pollita (pollita)   
rasmus (rasmus)   
salathe (salathe)   
sergey (sergey)   
stas (stas)   
svpernova09 (svpernova09)   
zimt (zimt)   
Final result: 14 3 1
This poll has been closed.

“As many expressions as feasible” includes expressions that provably don't reference the outer variable scope, such as

  • new X()
  • (new X())→propName
  • function($x) { return $x*$x; }
Support calls in static property declarations
Real name No Whitelist of global functions Any function or method call, even when the returned value contains references or arrays As many expressions as feasible (not referring to the variable scope)
bishop (bishop)    
bwoebi (bwoebi)    
carusogabriel (carusogabriel)    
dmitry (dmitry)    
galvao (galvao)    
ircmaxell (ircmaxell)    
jbnahan (jbnahan)    
kalle (kalle)    
ocramius (ocramius)    
pierrick (pierrick)    
pollita (pollita)    
rasmus (rasmus)    
salathe (salathe)    
sergey (sergey)    
svpernova09 (svpernova09)    
zimt (zimt)    
Final result: 12 2 0 2
This poll has been closed.

.

Support calls in static variables
Real name No Whitelist of global functions Any function or method call, even when the returned value contains references or arrays As many expressions as feasible (not referring to the variable scope)
bishop (bishop)    
bwoebi (bwoebi)    
carusogabriel (carusogabriel)    
dmitry (dmitry)    
galvao (galvao)    
jbnahan (jbnahan)    
kalle (kalle)    
marandall (marandall)    
ocramius (ocramius)    
pierrick (pierrick)    
pollita (pollita)    
rasmus (rasmus)    
salathe (salathe)    
sergey (sergey)    
svpernova09 (svpernova09)    
zimt (zimt)    
Final result: 14 2 0 0
This poll has been closed.

.

Support calls in parameter defaults
Real name No Whitelist of global functions Any function or method call, whether or not it returns a constant As many expressions as feasible (not referring to the variable scope)
bishop (bishop)    
bwoebi (bwoebi)    
carusogabriel (carusogabriel)    
dmitry (dmitry)    
galvao (galvao)    
ircmaxell (ircmaxell)    
jbnahan (jbnahan)    
kalle (kalle)    
marandall (marandall)    
ocramius (ocramius)    
pierrick (pierrick)    
pollita (pollita)    
rasmus (rasmus)    
salathe (salathe)    
sergey (sergey)    
stas (stas)    
svpernova09 (svpernova09)    
zimt (zimt)    
Final result: 14 3 0 1
This poll has been closed.

References

Rejected Features

Changing the behavior of instance properties was rejected. If functions were only invoked once, then private $x = generate_unique_id() would be unintuitive. If it was invoked for every created object, the implementation would require changes to internals that I'm probably unable to implement (these changes would affect unserialization, ways when object creation can throw, the behavior of internal functions that create and return objects, opcache, etc.)

rfc/calls_in_constant_expressions_poll.txt · Last modified: 2020/03/04 13:53 by tandre