Generate super tiny proxies for Symfony's dependency injection
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
lib
tests
.editorconfig
.gitignore
.travis.yml
Dockerfile
LICENSE
Makefile
README.md
composer.json
docker-compose.yml
phpunit.xml

README.md

Proxy generator for Symfony's DIC

Release Build Status Code Quality Code Coverage Packagist

This package provides a proxy generator for Symfony's dependency injection component that generates super tiny, super simple proxies, especially when compared to Symphony's default implementation.

If you're not familiar with proxy services, better have a look at Symfony's documentation before going any further.

The generator works with the following assumptions: the service we want to proxy implements an interface and services using that service expect that interface too. Pretty normal stuff. Consider the following code, where an ExceptionHandler service requires a logger implementing LogInterface:

<?php

use Psr\Log\LoggerInterface;

class ExceptionHandler
{
    private $logger;
    
    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }
    
    //
}

Now imagine we're using Monolog as a logger, and we have an expansive stream to setup. Why waste time building that logger for every request when it's seldom used? That's when we mark our service as lazy.

The following example demonstrates how we can mark our Psr\Log\LoggerInterface service as lazy (we could use PHP code or XML just the same):

services:

  Psr\Log\LoggerInterface:
    class: Monolog\Logger
    lazy: true
    #

The service can also use a factory:

services:

  Psr\Log\LoggerInterface:
    factory: 'LoggerFactory::build'
    lazy: true
    #

We don't have to define our service with a class, we could use logger instead of Psr\Log\LoggerInterface just the same, except we would have to define class for the factory one.

Now let's see how to build our container.

Building the dependency injection container

The following code demonstrates how to build, compile, and dump a container:

<?php

use olvlvl\SymfonyDependencyInjectionProxy\FactoryRenderer;
use olvlvl\SymfonyDependencyInjectionProxy\InterfaceResolver\BasicInterfaceResolver;
use olvlvl\SymfonyDependencyInjectionProxy\MethodRenderer;
use olvlvl\SymfonyDependencyInjectionProxy\ProxyDumper;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;

$builder = new ContainerBuilder();

//
// Here we load our config, or build the container using clever PHP calls.
// We might event have some compile passes to add.
//

$builder->compile();

$dumper = new PhpDumper($builder);
$dumper->setProxyDumper(new ProxyDumper(
    new BasicInterfaceResolver(),
    new FactoryRenderer(new MethodRenderer)
));

/* @var string $containerFile */

file_put_contents($containerFile, $dumper->dump());

There you have it. We can use our container as usual and everything is awesome and cute.

What if my lazy service implements multiple interfaces?

The basic interface resolver will have a hard time figuring out which interface to implement if a service implements many. For instance, if a service was an instance of ArrayObject the following exception would be raised:

Don't know which interface to choose from for ArrayObject: IteratorAggregate, Traversable, ArrayAccess, Serializable, Countable.

We can specify which interface to implement using the proxy tag:

ArrayObject:
  lazy: true
  tags:
  - { name: proxy, interface: ArrayAccess }

And since symfony/dependency-injection v4.2 we can specify the interface to implement using the lazy attribute:

ArrayObject:
  lazy: ArrayAccess

Requirements

The package requires PHP 7.1 or later.

Installation

The recommended way to install this package is through Composer:

$ composer require olvlvl/symfony-dependency-injection-proxy

Cloning the repository

The package is available on GitHub, its repository can be cloned with the following command line:

$ git clone https://github.com/olvlvl/symfony-dependency-injection-proxy.git

Testing

The test suite is ran with the make test command. PHPUnit and Composer need to be globally available to run the suite. The command installs dependencies as required. The make test-coverage command runs test suite and also creates an HTML coverage report in build/coverage. If your environment doesn't meet the requirements you can run the tests with a container, run make test-container to create it.

The package is continuously tested by Travis CI.

Build Status Code Coverage

License

olvlvl/symfony-dependency-injection-proxy is licensed under the New BSD License - See the LICENSE file for details.