This was almost a series of quickies posts — while it’s impractical to dive deep on each/every one of these Symfony service configuration values, there is some value to briefly talking about each one and linking off to the official docs. There’s nothing worse than debugging a problem and finding a handful of service configurations you’ve never seen before.
The examples in this article all assume you’re using symfony’s yaml
configuration files, but everything should apply equally to the XML and PHP variants.
Finally — these are quick thoughts dashed off by someone without a huge amount of practical Symfony experience. If something seems off or funky that’s probably because it is off or funky. Corrections are warmly welcomed.
Service Configuration: Modern Symfony
autowire
The autowire configuration lets Symfony know you want to automatically pass parameters to the constructor of a service based on its type hints. It’s what I usually call automatic constructor dependency injection, and I’ve written more about it here.
tags
The tags configuration allows you to add a list of tags to your service configuration. These tags are primarily used to tell Symfony that this service should be considered for some special role in Symfony. For example, give your service the twig.extension
tag and Symfony will treat it as a twig extension when it initializes its twig template engine.
autoconfigure
The autoconfigure configuration, when set to true, tells the system to “automatically apply certain configuration to your services“.
That’s not the most useful description, is it?
To understand autoconfigure, you need to understand how Symfony has worked historically. If you wanted a service class to play a role in some other Symfony system, you would typically need to tag that service with a specific name, and then (maybe) apply some extra configuration.
If your service has autoconfigure set to true
, then Symfony will handle this automatically if your service class implements a specific interface or extends a certain class. For example, consider this code
use Symfony\Component\Console\Command\Command;
//...
$container->registerForAutoconfiguration(Command::class)
->addTag('console.command');
This is where Symfony tells the container
Hey — if a service is autoconfigured AND it extends the
Symfony\Component\Console\Command\Command
class, then automatically tag it with theconsole.command
tag
Then, when Symfony’s container sees the console.command
tag, it knows it should include the service as a command for the bin/console
command.
In practice, autoconfigure is an attempt to move the responsibility of “identifying a service class for a particular role” away from the service configuration and into PHP code. Extend the right class or implement the right interface, and Symfony will just know your class is meant to do something.
bind
The bind configuration is related to autowiring, in that it allows you to
- Tell Symfony what to pass in for arguments without a type hint
- Tell Symfony to pass in a different service than is indicated via the type hint
It’s important to note that for the second use-case, this new service will still need to either extend the type hint’s class or implement its interface, as that’s just how PHP work.
Service Configuration: Classes, Hierarchy, and Naming
alias
The alias configuration allows you to create a second name for your service, and will also allow you to alias a private service as public.
parent
The parent configuration lets your service inherit the configuration of another service in your system.
abstract
The abstract configuration allows you to link a service to an abstract PHP class. Without an abstract configuration, Symfony would try to instantiate the abstract class, which is a fatal PHP error.
class
As we’ve seen, the class configuration allows you to set the class name symfony should use when instantiating your service object.
synthetic
Symfony allows you to inject new services into the container at runtime. However you still need a configuration entry for the service you plan to inject. The synthetic configuration tells Symfony that you plan to inject a service at runtime.
We haven’t talked much about it, but Symfony’s container code is actually compiled. Whenever you make a change to the service configuration Symfony will regenerate a bunch of PHP code in the background. Unlike other container systems (we’re looking at you Magento 2) this process is (100%?) seamless and you don’t need to do any manual cache clearing during development to see service configuration changes.
Service Configuration: Object Instances
shared
The shared configuration, which defaults to true
, determines whether the service container will return the same instance of a service object every time (shared:true
) or if the service container will return a different instance of the service object every time (shared:false
). Another way to think about this is a shared service acts similar to singleton object, while a non-shared service acts similar to a regular object instantiation.
It sounds like Symfony had more complex ideas around object/container scope that have been deprecated since version 2.8.
public
A public service is a service you can access directly via the service container. A private service (public:false
) is a service that may not be accessed directly via the service container. In modern versions of Symfony, services are private by default.
factory
Symfony’s service systems gets developers out of the business of instantiating service objects directly — however, sometimes the service.yaml
configuration options aren’t powerful enough to instantiate your service the way you want. In these cases, the factory configuration allows you specify a class and method name that Symfony will use to instantiate your service object.
configurator
The configurator configuration allows you to provide a class and method that symfony will use to configure your service after it’s instantiated. That is, Symfony will pass the instantiated service object to this method and then your code will have a chance to configure it.
Service Configuration: Argument Injecting
arguments
The arguments configuration allows you to tell Symfony what values or services it should pass to a service object when instantiating it.
properties
The properties configuration allows you to set public properties on your service object.
calls
The calls configuration allows you to specify a method and list of arguments that Symfony will call instantiating the service. This is another way to get dependencies into your service object.
Service Configuration: Miscellaneous
deprecated
The deprecated configuration allows you to mark a particular service as deprecated (ths is software-speak for “we may remove this soon and you probably don’t want to use it”). These deprecation messages will end up in the Symfony logs, as well as the default Symfony developer toolbar.
file
The file configuration allows you to load a PHP file right before your service is loaded. Two things that might trip you up
- You need to use the full, non-relative, path to the file. The
%kernel.root_dir%
parameter-variable is useful here. -
If you’re loading resources with the
resource
configuration, you’ll need to include your file in theexclude
list.
This seems like a useful, but old, configuration field. I would not be surprised to see this one go away in a future version of Symfony.
decorates, decoration_inner_name, and decoration_priority
Symfony’s services contain an implementation of the decorator pattern. The decorator pattern is — poorly named, and usually poorly explained (although this video does a pretty good job of it, if you can stand “enthusiastic YouTube persona”).
The elevator pitch for decorators is instead of creating a hierarchy of classes, it creates a hierarchy of object instantiation. An object is instantiated, and then passed to the constructor of a second object, and then that object is passed to the constructor of a third object, etc. If you’ve ever used middleware in Laravel you’ve been using something implemented with the decorator (or a decorator-like) pattern.
lazy
When a service is configured with lazy:true
, this tells Symfony that it should defer instantiating the service object until a method on that service object is actually called. This magic is implemented via the Proxy design pattern.
Configurations Not Directly Related to a Service
_defaults
The _defaults configuration lives under the services:
key, but is not a service configuration
#File: config/services.yaml
services:
_default:
#...
This configuration field allows you to set a configuration value for all your services — i.e. a default value. It works for most of the service configuration values we’ve discussed so far, and Symfony will complain with a useful message if you try to set something that’s not allowed in _default.
parameters
The parameters configuration lives at the top level of the services configuration
#File: config/services.yaml
parameters:
locale: 'en'
# ...
services:
# ...
The parameters section of your configuration allows you to set values that can be used later on via services template variable. i.e. you’d be able to reference the value of locale
later on in your service configuration via the string %locale%
.
resource, exclude
You can use the resource and exclude configuration to import many services at once directly from PHP classes. The syntax is a little weird, as it looks like a service configuration
services:
App\:
resource: '../src/*'
exclude: '../src/{Entity,Migrations,Tests,Kernel.php}'
These configuration fields live under a PHP namespace prefix that lives under the services:
key. These two configuration fields are covered in greater detail in the Symfony: Autowiring Services article.
imports
The imports configuration lives at the top level of a service configuration file
#File config/services.yaml
imports:
#...
services:
#...
The imports section allows you to load service configurations from other files, and is primarily useful as an organizational tool.