Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP static factory method: dynamically instantiate instance of the calling class

This PHP question is related to this question, but is a bit different. I have a static factory method called create() which instantiates a class instance. I want the method to dynamically instantiate an instance of the (sub)class on which it is called. So, the class it instantiates must be determined at runtime. But I want to do this without having to redefine the static factory method in the subclass (and this would be perfectly valid in my example since the subclass has no new data members to initialize). Is this at all possible?

class Foo {

  private $name;

  public static function create($name) {

    //HERE INSTED OF:
    return new Foo($name);
    //I WANT SOMETHING LIKE:
    //return new get_class($this)($name);//doesn't work
    //return self($this);//doesn't work either

  }

  private function __construct($name) {

    $this->name = $name;

  }

  public function getName() {

    return $this->name;

  }

}

// the following class has no private data, just extra methods:

class SubFoo extends Foo {

  public function getHelloName() {

    echo "Hello, ", $this->getName(), ".\n";

  }

}


$foo = Foo::create("Joe");
echo $foo->getName(), "\n"; // MUST OUTPUT: Joe

$subFoo = SubFoo::create("Joe");
echo $subFoo->getHelloName(), "\n"; // MUST OUTPUT: Hello, Joe.
like image 351
John Sonderson Avatar asked Feb 15 '15 17:02

John Sonderson


2 Answers

You must create object using Late Static Binding - method get_called_class() is useful. Second option is use static keyword.

Example:

class Foo 
{
    private $name;

    public static function create($name) 
    {
        $object = get_called_class();
        return new $object($name);
    }

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

    public function getName() 
    {
        return $this->name;
    }
}

class SubFoo extends Foo 
{
    public function getHelloName() 
    {
        return "Hello, ". $this->getName();
    }
}

$foo = Foo::create("Joe");
echo $foo->getName(), "\n";

$subFoo = SubFoo::create("Joe");
echo $subFoo->getHelloName(), "\n";

And output:

Joe
Hello, Joe
like image 52
Piotr Olaszewski Avatar answered Oct 14 '22 12:10

Piotr Olaszewski


return new static();

there is already reserved keyword static

like image 25
Kamil Karkus Avatar answered Oct 14 '22 12:10

Kamil Karkus