views:

181

answers:

1

How would one typically create a dynamic factory method in PHP? By dynamic factory method, I mean a factory method that will autodiscover what objects there are to create, based on some aspect of the given argument. Preferably without registering them first with the factory either. I'm OK with having the possible objects be placed in one common place (a directory) though.

I want to avoid your typical switch statement in the factory method, such as this:

public static function factory( $someObject )
{
    $className = get_class( $someObject );
    switch( $className )
    {
        case 'Foo':
            return new FooRelatedObject();
            break;
        case 'Bar':
            return new BarRelatedObject();
            break;
        // etc...
    }
}

My specific case deals with the factory creating a voting repository based on the item to vote for. The items all implement a Voteable interface. Something like this:

Default_User implements Voteable ...
Default_Comment implements Voteable ...
Default_Event implements Voteable ...

Default_VoteRepositoryFactory
{
    public static function factory( Voteable $item )
    {
        // autodiscover what type of repository this item needs
        // for instance, Default_User needs a Default_VoteRepository_User
        // etc...
        return new Default_VoteRepository_OfSomeType();
    }
}

I want to be able to drop in new Voteable items and Vote repositories for these items, without touching the implementation of the factory.

+2  A: 

If the switch statement is out you're basically down to naming conventions. Take the class of the passed in object and use it to instantiate the new class. Simple example below.

//pseudo code, untested
class Default_VoteRepositoryFactory
{
    public static function factory( Voteable $item, $arg1, $arg2 )
    {
        $parts = explode('_', get_class($item));
        $type  = array_pop();
        $class = 'Default_VoteRepository_' . $type;
        return new $class($arg1, $arg2);
        // autodiscover what type of repository this item needs
        // for instance, Default_User needs a Default_VoteRepository_User
        // etc...
    }
    //can be as complex or as simple as you need
    protected static function getType(stdClass $item)
    {
        $parts = explode('_', get_class($item));
        return array_pop($parts);       
    }
}
Alan Storm