Question

I am trying to create a new object, assign one of it's member's a value and then assign that object to an array key in a single statement.
IE:

class MyObj {
  public $member = 'sad';
}

$myArray = array(
  'key' => ((new MyObj())->member = 'happy')
);

The problem is this gives me a syntax error: "syntax error, unexpected '='"

The following code is a work around:

$obj = new MyObj();
$obj->member = 'happy';
$myArray = array(
  'key' => $obj
);

The question is why doesn't the single statement work? Why does it produce the syntax error? Finally, how can I create a single statement that creates a new object, assigns one of the member variables a value, and then associates that object with a key in an array?

Was it helpful?

Solution

First of all I want to say that this is a good question. I don't know why it is not working but there is a simple workaround by using a constructor with a parameter to set the member variable. In fact the construct function is made for triggering code when you initialize an object, and this is exactly what you are trying.

class MyObj {
  public $member;
  public function __construct($x){
    $this->member=$x;
  }
}

$myArray = array(
  'key' => new MyObj('happy')
);

print_r($myArray);

EDIT: I found that accessing a class during initialisation was not possible prior php version 5.4.0. I'm using php 5.4.12 and can't make this work either but it should work, because it is a new feature added since version 5.4.0.

http://docs.php.net/manual/en/migration54.new-features.php

Class member access on instantiation has been added, e.g. (new Foo)->bar().

EDIT: After some testing I came up with this example that actually works. When you try to initialize a new object and access its properties at the same time you are -per definition- chaining methods. This was not possible before php version 5.4.0. If you're using php >= 5.4 you can do this. To initialise an object and access its properties at the same time you need to make sure that the previous method call returns the object (new Obj returns the object automatically). PHP doesn't do this automatically so you need to do return $this manually. See next edit to get a workaround for this.

class MyObj {
  public $member;
  public function setMember($x){
    $this->member=$x;
    return $this;
  }
}

$myArray = array(
  'key' => (new MyObj)->setMember('happy')
);

print_r($myArray);

Note that the member variable is set by a method that returns the object.

EDIT: (11/02/14)

I've made a class to make methods from child classes chainable without having to return $this manually. It also can enable and disable method chaining so you can do both without returning $this when not needed (see start() and stop() methods)

Class Chainable{
    private  $chaining;//boolean

    public function __call($method,$arguments) {
        if(method_exists($this, $method)) {
            //$res=call_user_func_array(array($this,$method),$arguments);

            if($this->chaining ){
                if(!isset(call_user_func_array(array($this,$method),$arguments))){
                    return $this;
                }
                else{
                    echo "you can't chain methods that return something";
                            //however you could add the returned values to an array 
                            //(ie $this->returnedvalues)
                }   
            }

        }
    }
    private function setChaining($x){
        $this->chaining=$x;
    }
    public function start(){
        $this->setChaining(1);
        return $this;
    }
    public function stop(){
        $this->setChaining(0);
        return $this;
    }
}

How to use: Chainable methods must be private or protected. Public methods won't be called by the parents __call() method (Chainable class) because they are out of scope.

Class Foo extends Chainable{
    public $par1;
    public $par2;

    protected function setPar1($x){
        $this->par1=$x;
    }
    protected function setPar2($y){
        $this->par2=$y;
    }
    public function getPar1(){//public functions are not visible to the __call method from parent class.
        return $this->par1;
    }
    public function getPar2(){
        return $this->par2;
    }
    protected function printPar1(){
        echo $this->par1;
    }
    protected function printPar2(){
        echo $this->par2;
    }
}

$test=(new Foo())->start()//start chaining, set boolean true
                 ->setPar1('hello')//chained method calls...
                 ->setPar2('world')
                 ->printPar1()
                 ->printPar2()
                 ->stop();//stop chaining

$test->setPar1('hi');//normal method calls...
$test->setPar2('you');
echo '<br>'.$test->getPar1().' '.$test->getPar2();
$test->start()->setPar1('bonjour')->setPar2('soleil');//start chaining again
$test->stop();

OTHER TIPS

The mistake you are making is that you are trying to set a property on instantiation. PHP >= 5.4 only supports access to methods on instantiation.

Taking your class as an example:-

class MyObj {
  public $member = 'sad';
}

This:-

(new MyObj())->member = 'happy' 

is not supported and will produce unexpected results.

Methods, however, will work, as pointed out by kasper Taeymans. However, they must return something to be useful as the instantiated class is discarded unless returned by the called function, which is why kasper Taeymans' example works.

However, you are not restricted to returning $this, you can return anything you want:-

class MyObj {
  public $member = 'sad';

  public function getMember()
  {
     return $this->member;
  }
}

$member = (new MyObj())->getMember();//$member now === 'sad';

I just felt it was important to clarify that anything can be returned from methods called on instantiation this way.

Appears to be a restriction in the grammar and its just not supported. Or probably because new is a language construct and not an expression. Similar to why up until PHP 5.5.0 you couldn't pass an expression to empty() but only pure variables.

http://us2.php.net/empty

5.5.0
empty() now supports expressions, rather than only variables.

I would not expect this to work. The new keyword returns a new object instance of the class, and php does not let you write directly to a return value.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top