Re: [RFC] Allow calls to global functions in constant expressions

This is only part of a thread. view whole thread
  108580
February 14, 2020 15:18 tysonandre775@hotmail.com (tyson andre)
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
  108587
February 14, 2020 17:54 tysonandre775@hotmail.com (tyson andre)
> - 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
Then again, it's already possible to get function parameters through debug_backtrace(), so implicitly creating a closure and call with 0 bind vars wrapping the function calls might be an acceptable tradeoff. - Possibly leave that closure out for calls known to not be dynamic internal calls - It might make sense to blacklist known function names such as func_get_args(), get_defined_vars(), etc to prevent writing that type of buggy code, e..g. in parameter default expressions Thoughts?