Re: [RFC] Allow calls to global functions in constant expressions
| From: | tyson andre | Date: | Fri, 14 Feb 2020 15:18:17 +0000 |
| Subject: | Re: [RFC] Allow calls to global functions in constant expressions | ||
| References: | 1 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-108580@lists.php.net to get a copy of this message | ||
Hi internals,
https://wiki.php.net/rfc/calls_in_constant_expressions has
hit some roadblocks in the implementation shortly after the last email.
I've been blocked on how to resolve them in the implementation in a way I'm certain would
work.
I had assumed the calling scope wouldn't have the below issues when I started working on this
RFC, but was mistaken.
- The helper method the C code uses,
zend_call_function(), will always act as though
strict_types=0. I'd consider this a blocker for declare(strict_types=1);
const X = intdiv("123", 2);. (Internally, zend_call_function adds a fake call frame
without a function, similar to what __get, invocations of error handlers, etc do, and that call
frame makes the parameter parsing helper macros of the invoked function treat it like
strict_types=0)
It may also be desirable to specify calls in constants always work like strict_types=1, to avoid
issues such as strpos($float, '.') being locale-dependent)
- Getting the class scope *of the constant declaration* to work properly with callable
(e.g. public $x = array_map('self::helperMethod', VALUES);).
This isn't an issue with only a whitelist.
- Solving the above two issues while continuing to throw for func_get_args(), get_defined_vars(),
etc.
get_defined_vars() would throw for dynamic calls, but the above approaches would act like
Currently, my best ideas to fix some of the 3 issues were:
- Create a fake zend_function placeholder in C with a placeholder name and add it to the internal
stack of calls (EG(current_execute_data)).
Currently, though, it's only possible to set strict_types=1 for user-defined functions.
- Create an actual closure when compiling the code, which would be evaluated the same way as
public $x = (static function() { return array_map('self::helperMethod', VALUES);
})()
(i.e. a closure without any use variables. The )
This would solve it, but the performance would be unexpectedly worse than expected, and that
would interfere with optimizations.
- Create an alternative to zend_call_function, but that would duplicate code and be error prone.
I'm not familiar enough with XDebug, NewRelic, uopz, and other replacements of
zend_vm_execute to know if those would be able to support that,
or if there would be even more issues I haven't thought up yet that would prevent .
Second, I realize it doesn't make much sense to restrain the constant expressions for parameter
defaults and class constants in the same way.
The RFC was coherent proposing allowing any function call in 5 places, but less coherent proposing a
whitelist of functions, even where those restrictions weren't necessary.
- It may be desirable to support many extra expression types in parameter defaults and static
property defaults
(function myFunc(object $x = new DefaultObject()) {})
but still limit class constants to the proposed whitelist of functions.
Third, I was considering a straw poll for this,
but don't know what's required to set one up.
It also didn't make sense to me without a solution to the roadblocks.
1. Desired expressions in param defaults (No change/Whitelisted functions/Any function/Any method +
new X()+others)
2. ... in static property defaults
3. ... in static variable defaults
4. ... in class constant values
5. ... in const X = ...
Thanks,
- Tyson