Hi internals,
I've created a straw poll at https://wiki.php.net/rfc/calls_in_constant_expressions_poll , to measure interest in allowing calls in different types of constant expressions.
If there aren't any problems with the poll structure or rules preventing creating a poll, I was going to add it to the rfc index page and move it to voting.
This poll was created to gather opinions on which of the below statement types would be desirable to change, and in which ways, before rewriting https://wiki.php.net/rfc/calls_in_constant_expressions .
It seems desirable to change some of these expression types (e.g. parameter defaults, static properties, static variable defaults) in different ways from others.
(e.g. forbidding static property declaration expression results from containing objects seems like a completely unnecessary limitation from trying to reuse the implementation, in retrospect).
This poll was created for feedback on whether changes to the following places had support, and what types of changes there were interest in.
- Initial values of static or instance properties. This poll only addresses static properties.
- Parameter defaults of functions, methods, and closures.
- Class constant values.
- Global constant values.
- Static variable default values.
I'd asked earlier about creating a poll in https://externals.io/message/108430 , but didn't receive a response.
Thanks,
- Tyson
I've created a straw poll at https://wiki.php.net/rfc/calls_in_constant_expressions_poll , to measure interest in allowing calls in different types of constant expressions.
I've yet to make my mind up for most circumstances, although I'm leaning
towards a general "No".
What I can't express on this strawpoll though, is that I would
unequivocally vote against "any function or method call" in all
circumstances.
--
Mark Randall
marandall@php.net
Hi internals,
I've created a straw poll at https://wiki.php.net/rfc/calls_in_constant_expressions_poll , to measure interest in allowing calls in different types of constant expressions.
If there aren't any problems with the poll structure or rules preventing creating a poll, I was going to add it to the rfc index page and move it to voting.
This straw poll has been moved to voting and added to the rfc index page. The poll will be closed on March 4th.
Thanks,
- Tyson
On Wed, Feb 19, 2020 at 12:58 PM tyson andre tysonandre775@hotmail.com
wrote:
Hi internals,
I've created a straw poll at
https://wiki.php.net/rfc/calls_in_constant_expressions_poll , to measure
interest in allowing calls in different types of constant expressions.
If there aren't any problems with the poll structure or rules preventing
creating a poll, I was going to add it to the rfc index page and move it to
voting.This straw poll has been moved to voting and added to the rfc index page.
The poll will be closed on March 4th.
The original motivation was, IIRC, to initialize class constants with an
expression. Following KISS, I feel we should constrain our efforts to that
scope, and that's how I voted: "Yes" on class constants and static members,
"No" on everything else.
As for implementation, we must manage the complexity. I'm a hard "No" on
restricting use to an arbitrary, variable list of blessed functions. It's a
dev UX nightmare to include a bevy of array_* functions but no str*
functions.
Consequently, the only way to safely initialize class constants and static
members is at run-time, and I can only think of one way to do it. Apologies
if this has already been suggested: taking a cue from C#, a static class
constructor (1) would allow us to have expression-initialized constants
and static members.
<?php
class Config {
public const URL = null; // compile time initialization
protected static $mtime = null; // compile time initialization
private static function __constructStatic() {
$env = json_decode(file_get_contents('config.json'));
self::URL = $env->url;
self::$mtime = filemtime('config.json');
}
public function reload() {
if (self::$mtime < filemtime('config.json'))
self::__constructStatic();
}
}
}
echo Config::URL; // assert: runtime has already called _constructStatic
$config = new Config; // assert: __constructStatic called only once by
runtime
$config->reload(); // instance may call its own static constructor
?>
Trying to do the same for global constants, static variables, or function
default parameters resists a similar initialization mechanism because we
don't have defined common entry point analogues. If we had a main(), or if
we had framed @before decorators, we could do something similar, but we
don't -- so I feel we should leave these off the table.
Thank you, Tyson, for taking the time to progress this feature.
Consequently, the only way to safely initialize class constants and static
members is at run-time, and I can only think of one way to do it. Apologies
if this has already been suggested: taking a cue from C#, a static class
constructor ([1]) would allow us to have expression-initialized constants
and static members.<?php
class Config {
public const URL = null; // compile time initialization
protected static $mtime = null; // compile time initialization
private static function __constructStatic() {
$env = json_decode(file_get_contents('config.json'));
self::URL = $env->url;
self::$mtime = filemtime('config.json');
}
public function reload() {
if (self::$mtime < filemtime('config.json'))
self::__constructStatic();
}
}
}echo Config::URL; // assert: runtime has already called _constructStatic
$config = new Config; // assert: __constructStatic called only once by
runtime
$config->reload(); // instance may call its own static constructor
?>Trying to do the same for global constants, static variables, or function
default parameters resists a similar initialization mechanism because we
don't have defined common entry point analogues. If we had a main(), or if
we had framed @before decorators, we could do something similar, but we
don't -- so I feel we should leave these off the table.
For different reasons than this RFC I have wanted a static class constructor for a really long time.
I hope this is something we can seriously consider. Thanks Bishop for proposing it.
-Mike
The original motivation was, IIRC, to initialize class constants with an expression.
Following KISS, I feel we should constrain our efforts to that scope, and that's how I voted:
"Yes" on class constants and static members, "No" on everything else.
I'd also personally found the static $x = null; if ($x === null) { $x = some_fn(); }
pattern inconvenient and wanted that to be just static $x = some_fn();
to make the initial value some_fn()
if possible. It also seemed more readable (e.g. doesn't matter if some_fn() can be constant).
My personal use case for parameter defaults and global constants isn't as strong (especially with define()
),
but it's still something I'd want.
- I'd be able to use
private const FOO_DEFAULT = array_keys(...); function foo($x = FOO_DEFAULT) {}
if constants did pass, so that's less off a concern, and ensures&makes clear that the expression is only evaluated once, so it might be a better place to start with.
As for implementation, we must manage the complexity.
I'm a hard "No" on restricting use to an arbitrary, variable list of blessed functions.
It's a dev UX nightmare to include a bevy of array_* functions but no str* functions.
If the RFC succeeded with a whitelist, I'd planned to create RFCs to add to the whitelist.
Locale dependency of string functions was the reason for leaving it out initially, since that may also be a hard "no" for others.
Consequently, the only way to safely initialize class constants and static members is at run-time, and I can only think of one way to do it.
Apologies if this has already been suggested: taking a cue from C#, a static class constructor ([1])
would allow us to have expression-initialized constants and static members.
<?php
class Config {
public const URL = null; // compile time initialization
protected static $mtime = null; // compile time initialization
private static function __constructStatic() {
$env = json_decode(file_get_contents('config.json'));
self::URL = $env->url;
self::$mtime = filemtime('config.json');
}
public function reload() {
if (self::$mtime < filemtime('config.json'))
self::__constructStatic();
}
}
}echo Config::URL; // assert: runtime has already called _constructStatic
$config = new Config; // assert: __constructStatic called only once by runtime
$config->reload(); // instance may call its own static constructor
?>
This seems to allow the same functionality my RFC would allow, in a slightly different way.
I didn't go with that syntax because it'd move the values of the constants/properties away from the declaration.
Also, if json_decode()
threw, then there would never be a way for a PHP implementation to initialize self::$mtime
in that example, even though they're unrelated in how they're initialized there.
Allowing calling __constructStatic
multiple times (thus assigning to the const self::URL
multiple times) would be a significant change to php internals, and out of the scope of this RFC
https://wiki.php.net/rfc/calls_in_constant_expressions_poll ("Put the RFC(Poll) URL into all your replies.")
- Tyson
On Mon, Feb 17, 2020 at 3:09 AM tyson andre tysonandre775@hotmail.com
wrote:
Hi internals,
I've created a straw poll at
https://wiki.php.net/rfc/calls_in_constant_expressions_poll , to measure
interest in allowing calls in different types of constant expressions.
If there aren't any problems with the poll structure or rules preventing
creating a poll, I was going to add it to the rfc index page and move it to
voting.This poll was created to gather opinions on which of the below statement
types would be desirable to change, and in which ways, before rewriting
https://wiki.php.net/rfc/calls_in_constant_expressions .
It seems desirable to change some of these expression types (e.g.
parameter defaults, static properties, static variable defaults) in
different ways from others.
(e.g. forbidding static property declaration expression results from
containing objects seems like a completely unnecessary limitation from
trying to reuse the implementation, in retrospect).
This poll was created for feedback on whether changes to the following
places had support, and what types of changes there were interest in.
- Initial values of static or instance properties. This poll only
addresses static properties.- Parameter defaults of functions, methods, and closures.
- Class constant values.
- Global constant values.
- Static variable default values.
I'd asked earlier about creating a poll in
https://externals.io/message/108430 , but didn't receive a response.Thanks,
- Tyson
Hey Tyson,
I feel like the results of this poll aren't going to be particularly
meaningful, because it gets too caught up in the details and loses track of
the big picture.
If you ask people whether they want to allow
function test($param = some_call()) {
}
they're going to to tell you "no", because that seems pretty esoteric and
most people likely do not see a use-case for it.
If you ask the same people whether they want to write
function test(Dep $optionalDep = new Dep()) {
}
instead of
function test(Dep $optionalDep = null) {
if ($optionalDep === null) {
$optionalDep = new Dep();
}
}
a lot of them are probably going to tell you "yes" now. The question didn't
really change (new Dep is just a different type of "function call"), but
the perception changes a lot.
This is also why I think the focus on plain function calls in particular is
somewhat detrimental. This is one of the cases where going for a paradigm
shift (constant expression -> any expression) is "simpler" than doing an
incremental change (extending constant expressions to allow function calls,
and all the subtleties that entails.)
Regards,
Nikita
I feel like the results of this poll aren't going to be particularly
meaningful, because it gets too caught up in the details and loses track of
the big picture.
I'd definitely agree. If I was writing the RFC for calls in constant expressions again,
I'd focus more on adding concrete examples of where function calls/other expressions would make code easier to understand,
rather than focusing on implementation details.
At the time of writing the RFC, I thought a major objection would be whether or not it was actually feasible to implement,
and many people would be familiar with use cases where function calls in expressions would have made code more straightforward.
If you ask people whether they want to allow
function test($param = some_call()) {
}they're going to to tell you "no", because that seems pretty esoteric and
most people likely do not see a use-case for it.If you ask the same people whether they want to write
function test(Dep $optionalDep = new Dep()) { }
instead of
function test(Dep $optionalDep = null) {
if ($optionalDep === null) {
$optionalDep = new Dep();
}
}
a lot of them are probably going to tell you "yes" now. The question didn't
really change (new Dep is just a different type of "function call"), but
the perception changes a lot.
Good example, I hadn't thought of mentioning new
as an example for the "as many expression types as possible".
That also lets functions clearly enforce arguments are non-null.
This is also why I think the focus on plain function calls in particular is
somewhat detrimental. This is one of the cases where going for a paradigm
shift (constant expression -> any expression) is "simpler" than doing an
incremental change (extending constant expressions to allow function calls,
and all the subtleties that entails.)
The point of https://wiki.php.net/rfc/calls_in_constant_expressions_poll was to measure interest in "any expression",
but did a poor job of mentioning arguments in favor of it or how it'd simplify common examples.
With better arguments and examples, though, I'm still not certain if it'd be a 2/3 majority for any option.
A straw poll or RFC arguing only in favor of a paradigm shift with better arguments and examples
might see different results.
- Tyson