Make Module Configs Cacheable with the ZF2 Factory Interfac

For the longest time, I’ve been using closures in my Zend Framework 2 Modules Module class. I know they’re not always the best approach, but they’re not necessarily wrong either.

But after reviewing Gary Hockin’s recent talk at PHP Conference UK, I was reminded that outside of APC and OPCache, closures aren’t cacheable.

Depending on your application, this may not be a problem. But as most projects, invariably, grow over time, it’s likely they’ll inevitably become a performance bottleneck.

Gladly, he reminded me that there are alternative approaches which do allow for caching with Memcached, Redis and so on; specifically – if your configuration is based on a class which implements Zend\ServiceManager\FactoryInterface.

So in today’s tutorial, I’m going to show you a simple example of how to migrate from closures using this approach.

Standard Closure Approach

Ok, firstly here’s what a sample configuration in an app I’m making looks like:

class Module
    public function getServiceConfig()
    return array(
        'factories' => array(
                'Form\Feed\DeleteForm' => function ($sm) {
                    $form = new DeleteFeedRecordForm();
            new DeleteFeedRecordInputFilter()
                return $form;

You can see that I’ve setup a service manager service entry, Form\Feed\DeleteForm, by using a simple closure, instantiating the form, specifying a validation group and input filter, then returning the instantiated form.

For the purposes of today’s tutorial, this will work just nicely. Let’s see how we could migrate it.

Using The Factory Interface

To implement the FactoryInterface approach, we’ll need to create a class which implements Zend\ServiceManager\FactoryInterface. Below is my class. Have a look, then let’s go over it.

namespace BabyMonitor\ServiceManager\Form\Feed;

use Zend\ServiceManager\FactoryInterface,
    BabyMonitor\Form\DeleteFeedRecordForm as DeleteForm,
    BabyMonitor\InputFilter\DeleteFeedRecordInputFilter as DeleteFilter;

class DeleteFormFactory implements FactoryInterface
    public function createService(ServiceLocatorInterface $serviceLocator)
        $form = new DeleteForm();
             ->setInputFilter(new DeleteFilter());
        return $form;

As it’s configuring a service for the ServiceManager, providing a Form, managing deletion of feeds, BabyMonitor\ServiceManager\Form\Feed\DeleteFormFactory, the class namespace is semi-intuitive.

The factory interface only defines one required function, createService. I’ve included the use statements for the required classes and largely copied the code, verbatim, from the closure. Nice and simple.

Note: I’ve aliased the classes only for the purposes of readability and formatting. No real requirement otherwise.

Updating Module.php

With the class defined, I can now update getServiceConfig() by replacing our existing configuration with the one below:

'Form\Feed\DeleteForm' => 'BabyMonitor\ServiceManager\Form\Feed\DeleteFormFactory',

That’s it! Just one class (per/closure), and update the Module configuration. Assuming this was the only only configuration needing migration, we could then enable caching, as Akrabat explains.

Winding Up

Admittedly these were trivial examples, and depending on your configurations, you may need to go to a bit of effort to migrate your closures. But I hope you see that the migration’s quite straight-forward to do.

Share This

About Matthew

Matthew Setter Matthew Setter is a software developer specializing in PHP, Zend Framework, and JavaScript. He's also the host of, the podcast about the business of freelancing as a software developer and technical writer, and editor of Master Zend Framework, dedicated to helping you become a Zend Framework master?.

Find Matthew on LinkedIn Find Matthew on Twitter Find Matthew on Facebook Find Matthew on Google+

Like That?

Don’t miss the next post. Drop your email in the box below, and get it straight to your inbox, PLUS exclusive content only available by email. No spam, and you can unsubscribe at any time.