tags:

views:

970

answers:

2

I have a class with a factory-pattern function in it:

abstract class ParentObj {
    public function __construct(){ ... }
    public static function factory(){
        //returns new instance
    }
}

I need children to be able to call the factory function and return an instance of the calling class: $child = Child::factory(); and preferably without overriding the factory function in the child class.

I have tried multiple different ways of achieving this to no avail. I would prefer to stay away from solutions that use reflection, like __CLASS__.

(I am using PHP 5.2.5 if it matters)

+1  A: 

If you can upgrade to PHP 5.3 (released 30-Jun-2009), check out late static binding, which could provide a solution:

abstract class ParentObj {
    public function __construct(){}
    public static function factory(){

        //use php5.3 late static binding features:
        $class=get_called_class();
        return new $class;
    }
}


class ChildObj extends ParentObj{

    function foo(){
       echo "Hello world\n";
    }

}


$child=ChildObj::factory();
$child->foo();
Paul Dixon
I'm playing with RC4 at the minute so I'll try some code shortly if no one else steps up in the meantime...
Paul Dixon
LSB seems to be the best solution that I can find on my own.Until I upgrade, the best I can come up with is to either pass the child name to factory() or define the name as a property and grab that from factory()
Austin Hyde
According to the PHP manual, there is a function called `get_called_class()` that works like `__CLASS__` http://us.php.net/manual/en/function.get-called-class.php
Austin Hyde
Ha! I didn't know about that, have amended the sample. Thanks (I answer many questions in the hope of learning something!)
Paul Dixon
Good way to learn. Someone famous once said that you don't truly learn something until you teach it.
Austin Hyde
A: 

In my humble opinion what you're trying to do makes no sense.

A factory pattern would work like this:

abstract class Human {}

class Child extends Human {}
class Fool  extends Human {}

class HumanFactory
{
    public static function get($token)
    {
        switch ($token)
        {
            case 'Kid' : return new Child();
            case 'King': return new Fool();
            default    : throw new Exception('Not supported');
        }
    }
}

$child = HumanFactory::get('Kid');
Philippe Gerber
Well, that's a full-blown factory pattern. I simply meant a static method to bypass the `new` operator and to provide readability and chaining to child classes.
Austin Hyde
why would you want to bypass the new operator?
Philippe Gerber
to use your example, new Child()->foo() doesn't work. by adding the "factory" method (as I use it), you can do Child::factory()->foo()->bar(), which is more readable (IMHO) than breaking it up over a few lines.I guess it's a matter of opinion, and to be fair, your implementation of a factory is a useful one. Just not for what I'm looking for.
Austin Hyde
you can use HumanFactory::get('Kid')->foo()->bar(). as foo() and bar() are methods inside the Human and/or Child class. ;-)
Philippe Gerber