Hi,
It's a common idiom in object-oriented languages to create an object and
then immediately call a method on it, such as (in C# or Java):
new DateTime ().ToString ()
However, PHP grammar does not work this way. You have to put an additional
round of parentheses around new clause, such as:
(new DateTime ())->format ('Y-m-d')
This is rather clunky for such a common scenario (you usually have to walk
all the way back to the beginning of the expression to fix it). I have a
pattern of using static factories in place of constructor just to avoid
extra parentheses. Besides, the issue is relatively easy to fix. I've done
and tested a change for grammar in this area. It's a slight adjustment to
definition of dereferencable:
dereferencable:
variable { $$ = $1; } | '(' expr ')' { $$ = $2; }
- | new_expr { $$ = $1; }*
| dereferencable_scalar { $$ = $1; }
;
There was a problem with shift/reduces though. PHP has a level of
complexity in new expression which other languages don't. It's variable
class instantiation, such as:
new $class (arguments)
Expressions in place of $class can be rather complex, though I don't think
they really need to be. For example, such stuff is allowed:
new $var[0]->prop (arguments)
— which seems redundant and confusing. My fix to the problem was to force
parentheses around complex expressions such as above:
new ($var[0]->prop) (arguments)
— while keeping simple cases of "new $class (arguments)" without change.
Yes, this moves parentheses from one place to another (and occasionally
breaks the old code) but frequency wise I think it's an improvement.
What do you think?
Jaroslav Wegner
I really like the proposal and it's definitely improving more common modern
use cases.
However, I understand why the precedence is like that now in PHP to begin
with and so I think this should target PHP 8.
This change would be a bit similar to other weird use cases of variables
which were changed with PHP 7.
Best,
Harry
On Thu, 8 Feb 2018 at 20:45 Mcmuffin Mcguffin mcmuffinmcguffin@gmail.com
wrote:
Hi,
It's a common idiom in object-oriented languages to create an object and
then immediately call a method on it, such as (in C# or Java):new DateTime ().ToString ()
However, PHP grammar does not work this way. You have to put an additional
round of parentheses around new clause, such as:(new DateTime ())->format ('Y-m-d')
This is rather clunky for such a common scenario (you usually have to walk
all the way back to the beginning of the expression to fix it). I have a
pattern of using static factories in place of constructor just to avoid
extra parentheses. Besides, the issue is relatively easy to fix. I've done
and tested a change for grammar in this area. It's a slight adjustment to
definition of dereferencable:dereferencable:
variable { $$ = $1; } | '(' expr ')' { $$ = $2; }
- | new_expr { $$ = $1; }*
| dereferencable_scalar { $$ = $1; }
;There was a problem with shift/reduces though. PHP has a level of
complexity in new expression which other languages don't. It's variable
class instantiation, such as:new $class (arguments)
Expressions in place of $class can be rather complex, though I don't think
they really need to be. For example, such stuff is allowed:new $var[0]->prop (arguments)
— which seems redundant and confusing. My fix to the problem was to force
parentheses around complex expressions such as above:new ($var[0]->prop) (arguments)
— while keeping simple cases of "new $class (arguments)" without change.
Yes, this moves parentheses from one place to another (and occasionally
breaks the old code) but frequency wise I think it's an improvement.What do you think?
Jaroslav Wegner
--
Haralan Dobrev
CTO @ Clippings.com
What do you think?
Jaroslav Wegner
Thanks for the hard work to figure out what the roots of this annoyance
is. This could land in the next PHP version, considering that many other
breaking changes were also allowed in the past, given the following
prerequisites:
- RFC with a 2/3 majority vote
- Tool to convert any possibly broken code into valid code (basically
putting parenthesis around any complexnew (...)()
). - Update to
https://github.com/php/php-langspec/blob/master/spec/10-expressions.md#the-new-operator
--
Richard "Fleshgrinder" Fussenegger
new $var[0]
Is that creating an instance of the class name stored in the 0th index of the array $var or is it creating an instance of the class name stored in $var and accessing the 0th index using ArrayAccess?
Cheers
Stephen
Great contribution, very sensible even if subtile.
Is the kind of change that improve a lot but cause some trouble to people
used to the old way or when upgrading legacy codebases.
2018-02-15 5:32 GMT-03:00 Stephen Reay php-lists@koalephant.com:
On 9 Feb 2018, at 01:38, Mcmuffin Mcguffin mcmuffinmcguffin@gmail.com
wrote:new $var[0]
Is that creating an instance of the class name stored in the 0th index of
the array $var or is it creating an instance of the class name stored in
$var and accessing the 0th index using ArrayAccess?Cheers
Stephen
--
--
Atenciosamente,
Pedro Lacerda
Is that creating an instance of the class name stored in the 0th index of
the array $var or is it creating an instance of the class name stored in
$var and accessing the 0th index using ArrayAccess?
As soon as $var gets involved, it should be prioritized above the new
operator. So it's equivalent of "new ($var[0])"
Jaroslav
Hi,
It's a common idiom in object-oriented languages to create an object
and
then immediately call a method on it, such as (in C# or Java):new DateTime ().ToString ()
However, PHP grammar does not work this way.
This would definitely be nice to have, and thanks for looking into what the necessary change would look like.
I think the next challenge is to work out the different ways a dynamic class construction could happen, and which ones:
a) will be unaffected by the change
b) are an error now and will be allowed after
c) are allowed now and will be an error after
d) will work in both versions but change behaviour
It's anything that falls into category (d) that is particularly problematic, as it means users will see odd bugs of they don't know about the change. The clearer we can make these examples, the better.
Contrary to other responses, I think this would definitely need to happen in a major version, as it is quite clearly a breaking change. There's not much that can be done to deprecate code relying on the current rules, but we can publicise how to make code that is compatible before and after.
Regards,
--
Rowan Collins
[IMSoP]
Hi,
I'm not… quite sure if it changes anything, but it seems worth pointing
out PHP has two syntaxes for new
. You can do new DateTime()
, but you
can /also/ do new DateTime
without the brackets.
So, while you can't do new DateTime()->format(DATE_ATOM)
, you can do
(new DateTime)->format(DATE_ATOM)
. This is just as short. It's only
for constructor calls requiring arguments that we get the problem.
It also makes me wonder if it's not dereferenceable because then new DateTime()
would be ambiguous: is it constructing a DateTime, or is it
invoking a newly-constructed DateTime as a function? Be aware that
__invoke can be implemented by a class to make its objects callable.
Thanks!
--
Andrea Faulds
https://ajf.me/