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. Here are some differences:
- Can proxy
final
classes. - Can only proxy classes with interfaces.
- The generated proxies are self-contained.
- The package is ~10Kb and doesn't have dependencies, other than
symfony/dependency-injection
of course. - The package can be removed once the proxies have been generated.
If you're not familiar with proxy services, better have a look at Symfony's documentation before going any further.
composer require olvlvl/symfony-dependency-injection-proxy
The generator works with the following assumptions: the service we want to proxy implements an interface, and services
using that service expect that interface, following the dependency inversion principle. Now, consider the following
code, where an ExceptionHandler
service requires a logger implementing LoggerInterface
:
<?php
use Psr\Log\LoggerInterface;
class ExceptionHandler
{
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
// …
}
Imagine we're using Monolog as logger, and we have an expansive stream to set up. Why waste time building the 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 ofPsr\Log\LoggerInterface
just the same, except we would have to defineclass
for the factory one.
Now let's see how to build our container.
The following code demonstrates how to build, compile, and dump a container:
<?php
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 even have some compiler passes to add.
// …
$builder->compile();
$dumper = new PhpDumper($builder);
$dumper->setProxyDumper(new ProxyDumper());
/* @var string $containerFile */
file_put_contents($containerFile, $dumper->dump());
There you have it. We can use our container as usual and everything is awesome.
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 thrown:
Don't know which interface to choose from for ArrayObject: IteratorAggregate, Traversable, ArrayAccess, Serializable, Countable.
We can specify the interface to implement using the lazy
attribute:
ArrayObject:
lazy: ArrayAccess
The project is continuously tested by GitHub actions.
This project adheres to a Contributor Code of Conduct. By participating in this project and its community, you are expected to uphold this code.
Please see CONTRIBUTING for details.
olvlvl/symfony-dependency-injection-proxy is released under the BSD-3-Clause.