9

Why do expressions that use the new keyword need parentheses in order to be utilized in chained execution? In AS3, for example, you don't need parentheses. In PHP is this a stylistic aid for the interpreter or is there a bigger reason that I'm not aware of? Is it an order of execution precedence issue?

Constructor chaining in PHP

Thanks to this question Chaining a constructor with an object function call in PHP I figured out the how…

The object definition

Aside: Apparently the magic method __construct always implicitly returns $this and if you explicitly return $this (or anything for that matter) no errors/warnings/exceptions will occur.

class Chihuahua
{
    private $food;

    function __construct( $food )
    {
        $this->food = $food;
    }

    function burp()
    {
        echo "$this->food burp!";
    }
}

Works

(new Chihuahua('cake'))->burp();

Does Not Work (but I wish it did)

new Chihuahua('cake')->burp();
Community
  • 1
  • 1
Mark Fox
  • 8,694
  • 9
  • 53
  • 75
  • 1
    Because the PHP syntax is a mess. Some things randomly work, others don't. – melpomene Dec 29 '12 at 00:49
  • 1
    @melpomene: I wouldn't classify it as a mess, just finicky. – Brad Christie Dec 29 '12 at 00:52
  • It looks like a quick way to add in method chaining from a new instance, by relying on operator precedence – leemeichin Dec 29 '12 at 00:54
  • 1
    @melpomene, PHP is a mess but not in this case. There's something called "operator precedence" thanks God. And I'm sure the OP will work his way around the big problem of adding 2 parenthesis more for the sake of correctness. – Shoe Dec 29 '12 at 08:20
  • @Jeffrey JavaScript also has something called "operator precedence" and you don't need the parens in JS (because `new` has higher precedence than method calls (and why wouldn't it?)). Your argument is invalid. – melpomene Dec 30 '12 at 00:10
  • @melpomene, it's a matter of standard. I prefer PHP standards in this case. – Shoe Dec 30 '12 at 02:47
  • It is also interesting to note that closures in PHP also are wrapped by parentheses. While not identical to chained executions possibly it's a side effect of the closure syntax. – Mark Fox Jan 22 '13 at 23:31

4 Answers4

10

I believe it is because the interpreter parses into this,

new (Chihuahua('cake')->burp());

instead of,

(new Chihuahua('cake'))->burp();

since -> has a higher preference than the new operator.

And giving you an error because this,

Chihuahua('cake')->burp()

is not understood. Hope it helps.

rae1
  • 6,066
  • 4
  • 27
  • 48
  • Annoyingly, the PHP manual doesn't include the operator precedence for `->`, but I'd assume that given the example, the `->` operator binds tighter than `new` (which is shown as highest precedence anyway :S) – slugonamission Dec 29 '12 at 00:57
  • I'll accept your assumption as correct because it's clear and seems sensibile. – Mark Fox Dec 29 '12 at 01:20
  • @rae1: In C#, `Dictionary d = new Dictionary();` compiles, but it doesn't work in my version of PHP. Might be a bug in my particular implementation. :) – OCDev Oct 03 '14 at 00:35
4

Because the new operator has a lesser priority than the -> operator. Php try to run Chihuahua('cake')->burp() before new Chihuahua('cake'). That is the problem.

Thomas Ruiz
  • 3,611
  • 2
  • 20
  • 33
  • Interestingly, the PHP docs do not list the object operator on the [Operator Precedence](http://php.net/manual/en/language.operators.precedence.php) page. – Wiseguy Dec 29 '12 at 00:55
  • @Jeffery I initially thought the same but the chosen answer essentially says the same and is better written. – Mark Fox Dec 30 '12 at 21:49
1

Not sure why you would be trying to do this but some things to note about php. First, yes you need to use the parenthesis around the new Object() statement to inline cast the call to the actual object.

With your example above here you are immediately throwing away the object after calling the burp method. If this is the case where you need an object method to just work without depending on an instance of said object why not just use static methods?

EDIT: Added in the __complex static method to show how to wrap a construct -> execute -> dispose process.

class Chihuahua
{
    public static function burp( $food )
    {
        echo "$food burp!";
    }

    protected $food = '';
    public function doBurp()
    {
        echo $this->food . " burp!";
    }

    public function __construct($food)
    {
        $this->food = $food;
    }

    public static __complex( $food )
    {
        $chi = new Chihuahua($food);
        $chi->doBurp();
        unset($chi);
    }
}

Chihuahua::burp("cake");
// - or
Chihuahua::__complex("cake");
  • Good point. I think a static call makes sense for a utility class, but there are cases where you'll need to utilize a complex object but don't need the overhead of retaining it in a variable. I've found that in the right context it helps clarify the fact that the object is used once in a certain scope. – Mark Fox Dec 29 '12 at 01:06
  • Static constructor emulator? public static function __complex($food) { $chi = new Chihuahua($food); $chi->burp(); unset($chi); } –  Dec 29 '12 at 01:19
0

Just a side note: constructor within parentheses only works for PHP v 5.4 and later. See http://3v4l.org/ZANaO vs http://3v4l.org/m9vk9

mlocati
  • 369
  • 3
  • 2