Lazy Services

Zend\ServiceManager can use delegator factories to generate “lazy” references to your services.

Lazy services are proxies that get lazily instantiated, and keep a reference to the real instance of the proxied service.

Use cases

You may want to lazily initialize a service when it is instantiated very often, but not always used.

A typical example is a database connection: it is a dependency to many other elements in your application, but that doesn’t mean that every request will execute queries through it.

Additionally, instantiating a connection to the database may require some time and eat up resources.

Proxying the database connection would allow to delay that overhead until the object is really needed.

Setup

`Zend\ServiceManager\Proxy\LazyServiceFactory is a delegator factory capable of generating lazy loading proxies for your services.

The LazyServiceFactory depends on ProxyManager, so be sure to install it before going through the following steps:

1
php composer.phar require ocramius/proxy-manager:0.3.*

Practical example

To demonstrate how a lazy service works, you may use the following Buzzer example class, which is designed to be slow at instantiation time for demonstration purposes:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
namespace MyApp;

class Buzzer
{
    public function __construct()
    {
        // deliberately halting the application for 5 seconds
        sleep(5);
    }

    public function buzz()
    {
        return 'Buzz!';
    }
}

You can then proceed and configure the service manager to generate proxies instead of real services:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
$serviceManager = new \Zend\ServiceManager\ServiceManager();

$config = array(
    'lazy_services' => array(
         // mapping services to their class names is required
         // since the ServiceManager is not a declarative DIC
         'class_map' => array(
             'buzzer' => 'MyApp\Buzzer',
         ),
    ),
);

$serviceManager->setService('Config', $config);
$serviceManager->setInvokableClass('buzzer', 'MyApp\Buzzer');
$serviceManager->setFactory('LazyServiceFactory', 'Zend\ServiceManager\Proxy\LazyServiceFactoryFactory');
$serviceManager->addDelegator('buzzer', 'LazyServiceFactory');

This will tell the service manager to use the LazyServiceFactory delegator factory to instantiate the buzzer service.

As you may have noticed, the standard setup for the LazyServiceFactory requires you to define a Config service. That’s because the functionality was thought to be easily integrated into Zend\Mvc.

You can now simply retrieve the buzzer:

1
2
3
$buzzer = $serviceManager->get('buzzer');

echo $buzzer->buzz();

To verify that the proxying occurred correctly, you can simply run the following code, which should delay the 5 seconds wait time hardcoded in Buzzer::__construct until Buzzer::buzz is invoked:

1
2
3
4
5
6
7
for ($i = 0; $i < 100; $i += 1) {
    $buzzer = $serviceManager->create('buzzer');

    echo "created buzzer $i\n";
}

echo $buzzer->buzz();

The setup above can also be represented via configuration in an MVC application’s context:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
return array(
    'service_manager' => array(
        'invokables' => array(
            'buzzer' => 'MyApp\Buzzer',
        ),
        'delegators' => array(
            'buzzer' => array(
                'LazyServiceFactory'
            ),
        ),
        'factories' => array(
            'LazyServiceFactory' => 'Zend\ServiceManager\Proxy\LazyServiceFactoryFactory',
        ),
    ),
    'lazy_services' => array(
        'class_map' => array(
            'buzzer' => 'MyApp\Buzzer',
        ),
    ),
);

Configuration

This is the config structure expected by Zend\ServiceManager\Proxy\LazyServiceFactoryFactory:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
return array(
    'lazy_services' => array(

        // map of service names and their relative class names - this
        // is required since the service manager cannot know the
        // class name of defined services upfront
        'class_map' => array(
            // 'foo' => 'MyApplication\Foo',
        ),

        // directory where proxy classes will be written - default to system_get_tmp_dir()
        'proxies_target_dir' => null,

        // boolean flag to indicate whether to generate proxies
        // proxies are auto-generated by default
        'auto_generate_proxies' => null,

        // namespace of the generated proxies, default to "ProxyManagerGeneratedProxy"
        'proxies_namespace' => null,

         // whether the generated proxy classes should be written to disk
         'write_proxy_files' => false,
    ),
);

Table Of Contents

Previous topic

Delegator service factories

Next topic

Session Config

This Page

Note: You need to stay logged into your GitHub account to contribute to the documentation.

Edit this document

Edit this document

The source code of this file is hosted on GitHub. Everyone can update and fix errors in this document with few clicks - no downloads needed.

  1. Login with your GitHub account.
  2. Go to Lazy Services on GitHub.
  3. Edit file contents using GitHub's text editor in your web browser
  4. Fill in the Commit message text box at the end of the page telling why you did the changes. Press Propose file change button next to it when done.
  5. On Send a pull request page you don't need to fill in text anymore. Just press Send pull request button.
  6. Your changes are now queued for review under project's Pull requests tab on GitHub.