rfc:calls_in_constant_expressions

# Differences

This shows you the differences between two versions of the page.

 rfc:calls_in_constant_expressions [2020/02/09 20:45]tandre rfc:calls_in_constant_expressions [2020/03/04 14:01] (current)tandre link to poll discussion Both sides previous revision Previous revision 2020/03/04 14:01 tandre link to poll discussion2020/03/04 13:56 tandre Withdrawn2020/03/04 13:55 tandre Close RFC2020/02/17 00:29 tandre 2020/02/13 23:53 tandre 2020/02/09 20:46 tandre 2020/02/09 20:45 tandre 2020/02/09 20:37 tandre Remove leftover documentation for instance properties2020/02/09 20:10 tandre Document that method calls are compile errors2020/02/09 19:32 tandre format2020/02/09 19:31 tandre Forbid calls in instance property defaults, add missing functions to the whitelist2020/02/09 02:42 tandre 2020/02/09 02:25 tandre created Next revision Previous revision 2020/03/04 14:01 tandre link to poll discussion2020/03/04 13:56 tandre Withdrawn2020/03/04 13:55 tandre Close RFC2020/02/17 00:29 tandre 2020/02/13 23:53 tandre 2020/02/09 20:46 tandre 2020/02/09 20:45 tandre 2020/02/09 20:37 tandre Remove leftover documentation for instance properties2020/02/09 20:10 tandre Document that method calls are compile errors2020/02/09 19:32 tandre format2020/02/09 19:31 tandre Forbid calls in instance property defaults, add missing functions to the whitelist2020/02/09 02:42 tandre 2020/02/09 02:25 tandre created Line 1: Line 1: ====== PHP RFC: Allow function calls in constant expressions ====== ====== PHP RFC: Allow function calls in constant expressions ====== - * Version: 0.3 + * Version: 0.5 - * Date: 2020-02-21 + * Date: 2020-02-16 * Author: Tyson Andre * Author: Tyson Andre - * Status: Under Discussion + * Status: Withdrawn * First Published at: https://wiki.php.net/rfc/calls_in_constant_expressions * First Published at: https://wiki.php.net/rfc/calls_in_constant_expressions Line 9: Line 9: Currently, constant expressions in declarations allow a limited set of expression types such as literals, constants, and operations. Currently, constant expressions in declarations allow a limited set of expression types such as literals, constants, and operations. - This RFC proposes allowing calls of global functions in some constant expressions. Calls would be allowed in declarations of class and global constants, defaults of static properties, static variables, and parameter defaults. + This RFC proposes allowing calls of a whitelist of global functions in some constant expressions. Calls would be allowed in declarations of class and global constants, defaults of static properties, static variables, and parameter defaults. This will allow calling functions such as ''\count()'', ''\array_merge()'', ''\array_keys()'', and ''\in_array()'', This will allow calling functions such as ''\count()'', ''\array_merge()'', ''\array_keys()'', and ''\in_array()'', An Error will be thrown if the call would be invalid to use within a constant (due to references or non-constant return values). An Error will be thrown if the call would be invalid to use within a constant (due to references or non-constant return values). - - Two secondary voting options are proposed for this: Allowing any function to be called, or allowing a small whitelist of deterministic functions. ===== Proposal ===== ===== Proposal ===== Line 22: Line 20: Function calls will be allowed in the following types of constant expressions: Function calls will be allowed in the following types of constant expressions: - * Defaults of static properties, but **not** instance properties, due to changes required to the PHP internals expanding the scope of this RFC too much.PHP currently evaluates all of the default values of instance properties of a class once, and permanently stores them. \\ This preserves PHP's current evaluation order (the first time a static property is used, all property default values are evaluated) + * Defaults of static properties, but **not** instance properties, due to changes required to the PHP internals expanding the scope of this RFC too much. PHP currently evaluates all of the default values of instance properties of a class once, and permanently stores them. \\ This preserves PHP's current evaluation order (the first time a static property is used, all property default values are evaluated) * Parameter defaults (expressions with function calls will always be evaluated each time the parameter is absent) * Parameter defaults (expressions with function calls will always be evaluated each time the parameter is absent) * Global constants (evaluated immediately) and class constants (evaluated and cached the first time they are successfully fetched) * Global constants (evaluated immediately) and class constants (evaluated and cached the first time they are successfully fetched) * Defaults of static variables (evaluated and cached the first time the expression succeeds) * Defaults of static variables (evaluated and cached the first time the expression succeeds) - A secondary Yes/No voting option is part of this RFC, to allow calling any global function, not just those in the whitelist. - That voting option reflects the differing opinions on what a constant is meant to be. - Allowing any function to be called in a constant expression will allow more flexibility for users, - but limiting function names to a whitelist will make side effects of uses of constants easier to reason about when developers read php code. - - - ==== Proposal for Whitelisting ==== - - If the secondary vote passes, any function (user-defined or internal) can be called. - It will be left to coding practice guidelines to assert that constants are only - used in safe ways. - If the secondary vote fails, then only functions in a whitelist of functions will be callable in constant expressions. + Only functions in the following whitelist of functions will be callable in constant expressions. Attempting to use other functions in constant expressions will be a fatal compile error. Attempting to use other functions in constant expressions will be a fatal compile error. This whitelist includes functions that are actually deterministic and without side effects, and don't depend on ini This whitelist includes functions that are actually deterministic and without side effects, and don't depend on ini Line 57: Line 44: ==== Behaviors in any constant expression ==== ==== Behaviors in any constant expression ==== + + Many of these edge cases aren't possible for functions in the whitelist, but will be checked for in the implementation. If a function call's result contains anything that is invalid for a constant (e.g. objects or reference cycles), If a function call's result contains anything that is invalid for a constant (e.g. objects or reference cycles), - an ''Error'' will be thrown and the result will be freed. (same as what ''define()'' would accept) + an ''Error'' will be thrown and the result will be freed. (same as what ''define()'' would accept). If a function call attempts to modify a parameter by reference, an ''Error'' will be thrown. If a function call attempts to modify a parameter by reference, an ''Error'' will be thrown. Line 66: Line 55: will all throw an ''Error'' if they are called in a function expression (through the same mechanism that already forbids them in dynamic calls). will all throw an ''Error'' if they are called in a function expression (through the same mechanism that already forbids them in dynamic calls). - Argument unpacking is allowed. (e.g. ''count(...[[1,2]])'') + Argument unpacking is allowed. (e.g. ''count(...[CONST_ARRAY])'') Function calls must be by name: Function calls must be by name: Line 91: Line 80: ==== Handling functions not in the whitelist ==== ==== Handling functions not in the whitelist ==== - A fatal CompileError will be emitted when including a file if any constant expression uses a function name that might be outside of the whitelist. + A fatal CompileError will be emitted when including a file if any constant expression uses a function name that is outside of the whitelist. Line 123: Line 112: ==== Whitelisted Functions ==== ==== Whitelisted Functions ==== - The following list of functions is proposed for the whitelist option of the secondary vote. Functions with the following properties were chosen. Functions with the following properties were chosen. Line 133: Line 121: For this reason, ''strlen()'', ''sprintf()'', and ''strpos()'' are omitted from the proposed whitelist. Those may be included in a followup RFC. For this reason, ''strlen()'', ''sprintf()'', and ''strpos()'' are omitted from the proposed whitelist. Those may be included in a followup RFC. - The list of functions that would be included in the whitelist is below: + The following list of functions is whitelisted. abs abs Line 242: Line 230: Opcache appears to be unaffected - tests of this RFC are passing. Opcache likely just fails to optimize the constant expressions ahead of time. Opcache appears to be unaffected - tests of this RFC are passing. Opcache likely just fails to optimize the constant expressions ahead of time. - In the future, if this gets adopted widely, support for optimizing calls in constant expressions may be desirable. + In the future, if this gets adopted widely, more aggressive optimizations of calls in constant expressions may be desirable. (e.g. permanently storing parameter defaults if the call is provably deterministic) + + Opcache already has the ability to optimize functions such as ''strlen'' at compile time, when using other constants from the same class. ==== New Functions ==== ==== New Functions ==== - If the whitelist approach is used, ''get_defined_functions_allowed_in_constant_expressions()'' will be added to PHP. + ''get_defined_functions_allowed_in_constant_expressions()'' will be added to PHP. - If any call is allowed in the secondary vote, that function won't be added. + ===== Future Scope ===== ===== Future Scope ===== Line 254: Line 243: * Allowing even more expression types in constant expressions, such as static method calls. * Allowing even more expression types in constant expressions, such as static method calls. - * Adding more groups of functions to the whitelist, if the secondary vote fails and a whitelist is used. (e.g. string functions such as ''strlen()'') + * Adding more groups of functions to the whitelist, or avoiding the whitelist approach. * Allowing function calls in the defaults of instance properties. * Allowing function calls in the defaults of instance properties. * Allowing non-constant defaults for instance properties, such as ''public $x = new Foo();''. * Allowing non-constant defaults for instance properties, such as ''public$x = new Foo();''. Line 260: Line 249: ===== Proposed Voting Choices ===== ===== Proposed Voting Choices ===== - Primary vote: Allow calling global functions **that are in the described whitelist** (Yes/No, Requires 2/3 majority) + Primary vote: Allow calling global functions that are in the described whitelist (Yes/No, Requires 2/3 majority) - Secondary vote: Allow calling any global functions, without a whitelist limitation (Yes/No, Requires 2/3 majority for "Yes" to pass) + Also see [[https://externals.io/message/108630|Straw poll: Places to allow function calls in constant expressions]] ===== Patches and Tests ===== ===== Patches and Tests ===== Line 272: Line 261: ===== References ===== ===== References ===== [[https://externals.io/message/108343|Planning an RFC to allow calls to global functions in constant expressions]] [[https://externals.io/message/108343|Planning an RFC to allow calls to global functions in constant expressions]] + + [[https://externals.io/message/108630|Straw poll: Places to allow function calls in constant expressions]] + + https://wiki.php.net/rfc/calls_in_constant_expressions_poll