php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #70549 Allow `new Foo()->bar()` without parens around `(new Foo)`
Submitted: 2015-09-22 07:04 UTC Modified: 2015-09-29 03:01 UTC
Votes:4
Avg. Score:4.5 ± 0.9
Reproduced:3 of 3 (100.0%)
Same Version:1 (33.3%)
Same OS:2 (66.7%)
From: vovan-ve at yandex dot ru Assigned: yohgaki (profile)
Status: Assigned Package: Scripting Engine problem
PHP Version: 7.1.0 OS:
Private report: No CVE-ID: None
 [2015-09-22 07:04 UTC] vovan-ve at yandex dot ru
Description:
------------
PHP 5.4 allowed us to chain member assess to `new Foo`, but there must be parens:

    (new Foo)->bar();
    (new Foo(42, 37))->bar();
    something((new Foo(42, 37))->lorem()->ipsum()->dolor());

Why do we need that redundant parenses? Compare what ECMAScript allows - you know:

    new Foo().method();
    new Foo().field;
    new some.where.Foo().method();
    new Foos[i]().method();
    new (anything)().method();

PHP 7 should to remove redundant parens.

Test script:
---------------
class Foo {
    protected $id;
    public function __construct($id) {
        echo "new ", get_called_class(), "($id)\n";
        $this->id = $id;
    }
    public function __toString() {
        return get_class($this) . "{" . $this->id . "}";
    }
    public function bar($x) {
        echo $this, "->", __FUNCTION__, "($x)\n";
        return $this;
    }
    public function val($x) {
        echo $this, "->", __FUNCTION__, "($x) => $x\n";
        return $x;
    }
    public function lorem(self $foo, $x) {
        echo $this, "->", __FUNCTION__, "($foo, $x)\n";
        $foo->bar($x);
        return $this;
    }
}

new Foo(10)->bar(20)->bar(30)->bar(new Foo(40)->val(50));
new Foo(60)->lorem(new Foo(70)->bar(80), new Foo(90)->val(100));
// same as
// (new Foo(10))->bar(20)->bar(30)->bar((new Foo(40))->val(50));
// (new Foo(60))->lorem((new Foo(70))->bar(80), (new Foo(90))->val(100));


Expected result:
----------------
new Foo(10)
Foo{10}->bar(20)
Foo{10}->bar(30)
new Foo(40)
Foo{40}->val(50) => 50
Foo{10}->bar(50)
new Foo(60)
new Foo(70)
Foo{70}->bar(80)
new Foo(90)
Foo{90}->val(100) => 100
Foo{60}->lorem(Foo{70}, 100)
Foo{70}->bar(100)


Actual result:
--------------
Parse error: syntax error, unexpected '->' (T_OBJECT_OPERATOR)

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-09-22 15:38 UTC] enoquejoseneas at gmail dot com
Good idea. PHP need this feature, already available on Java and Javascript
 [2015-09-25 07:07 UTC] kalle@php.net
-Status: Open +Status: Assigned -Assigned To: +Assigned To: nikic
 [2015-09-25 07:07 UTC] kalle@php.net
(assigning to Nikita for his PoV on this)
 [2015-09-25 07:17 UTC] nikic@php.net
-Assigned To: nikic +Assigned To:
 [2015-09-25 07:17 UTC] nikic@php.net
We currently allow code like this:

    $obj = new $foo->bar();
    // Meaning:
    $class = $foo->bar;
    $obj = new $class();

You are proposing to interpret this as $obj = (new $foo)->bar() instead, which would break backwards compatibility.

This could have been changed as part of the UVS RFC, but I felt like this change would be too intrusive and the consequences rather weird. I expect something like `new $foo['bar']` to behave as `new {$foo['bar']}` not `(new $foo)['bar']`.
 [2015-09-25 07:24 UTC] vovan-ve at yandex dot ru
> You are proposing to interpret this as `$obj = (new $foo)->bar()` instead

No, it's not. `new $foo->bar()->method()`
is exactly `new ($foo->bar)()->method()`
like `new foo.bar().method()` is ECMAScript.
 [2015-09-25 08:13 UTC] nikic@php.net
Ah, I think I get what you mean now. You only want to allow omission of parentheses if new is used with an argument list, correct?

I.e. `new Foo->bar()` will be forbidden, but `new Foo()->bar()` will be allowed and interpreted as `(new Foo())->bar()`?
 [2015-09-25 08:20 UTC] vovan-ve at yandex dot ru
nikic, Yes, right. `new Foo->bar()` start with `Foo->...` and it is "unexpected ->".
 [2015-09-25 13:57 UTC] nikic@php.net
In that case it should be very easy to support this. Something along these lines: https://gist.github.com/nikic/47ee4f5e67bc90866099 This allows `new Foo()->bar()`, `new Foo()->bar`, `new Foo()['bar']`. Adding it to callable vars as well would allow `new Foo()()`.

So from the technical side this is no problem. I don't know if we should actually allow it, as the syntax looks somewhat ambiguous. I'm neutral regarding that.

If we want this change, somebody should RFC it.
 [2015-09-29 03:01 UTC] yohgaki@php.net
-PHP Version: 7.0.0RC3 +PHP Version: 7.1.0 -Assigned To: +Assigned To: yohgaki
 [2015-09-29 03:01 UTC] yohgaki@php.net
@Nikic
Good news. I'll prepare RFC for 7.1.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 14:01:29 2024 UTC