ZF2 Autoloader: Use factory for base class on exte

2019-08-10 15:36发布

问题:

If I wanted to use the same factory for any class that extended my base class, would I want to turn the base class factory into a named function, or is there a better way to do this?

$serviceManager => array(
    'factories' => array(
        'someBaseClass' => function($thisServiceManager) {
            $db = $thisServiceManager->get('db');
            $thisBaseClass = new \myNamespace\thisBaseClass($db);
            return $thisBaseClass;
        },
    ),
);

EDIT

Further to the answer I accepted, here's the code I've tested that works.

Class File

use Zend\ServiceManager\AbstractFactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class baseClassFactory implements \Zend\ServiceManager\AbstractFactoryInterface
{
    public function canCreateServiceWithName (ServiceLocatorInterface $locator, $name, $requestedName = '')
    {
        return ('baseClass' === $name || is_subclass_of($name, 'baseClass'));
    }

    public function createServiceWithName (ServiceLocatorInterface $locator, $name, $requestedName = '')
    {
        $db = $locator->get('db');
        $query = new $name($db);
        return $query;
    }
}

Configuration

$serviceManager => array(
    'abstract_factories' => array(
        'baseClassFactory',
    ),
);

回答1:

If I'm following your question, you have a bunch of classes that extend someBaseClass, and you want them all to be manufactured in the same way?

If so, then that sounds like a good opportunity to use the abstract_factories component in the ServiceManager. The pseudo-code would be like:

// warning: untested pseudo-code
class MyAbstractFactory implements \Zend\ServiceManager\AbstractFactoryInterface {
    public function canCreateServiceWithName($_, $_, $name) {
        // if I'm asked for someBaseClass or a child of someBaseClass, return true: false otherwise
        return ('someBaseClass' === $name || is_subclass_of($name, 'someBaseClass'));
    }

    public function createServiceWithName($locator, $_, $name) {
        // your factory logic here
        // $object = ...
        return $object;
    }
}

And your config would look like:

$serviceManager = [ 'abstract_factories' => [ 'MyAbstractFactory' ] ];

Using the concrete factories, you'd have to repeat the same function for each extended class (AFAIK), which would be a pain to maintain (IMO). The abstract factory pattern above basically says: give me a class, I'll reflect it to see if it's the base class I care about and, if so, I'll run my factory to get it.

More info on abstract_factories if you've never used it before.