November 21, 2019 Javier Eguiluz

Symfony includes plenty of linters, which are commands that validate certain parts of the application (e.g. lint:yaml to check the syntax of all YAML config files; lint:twig to check the syntax of all Twig templates, etc.)

In Symfony 4 we added a new linter called lint:container . As you may have guessed, it checks the services defined in the container. Specifically, it ensures that arguments injected into services match type declarations.

Consider the following class created for a service:

1 2 3 4 5 6 7 8 9 namespace App\SomeNamespace ; class SomeService { public function __construct ( int $someProperty = 7 ) { // ... } }

If you now try to add the following service configuration:

1 2 3 # config/services.yaml services : App\SomeNamespace\SomeService : ~

You'll see the following error when running the lint:container command:

1 2 Invalid definition for service "App\SomeNamespace\SomeService": argument 1 of "App\SomeNamespace\SomeService::__construct" accepts "int", "NULL" passed.

The new container linter goes much further and it can detect errors like the following. Consider this class with a variadic method:

1 2 3 4 5 6 7 8 9 namespace App\SomeNamespace ; class SomeService { public function setSomeItems ( SomeClass $item , SomeClass ... $items ) { // ... } }

If you use the following service definition:

1 2 3 4 5 6 7 8 9 10 11 12 13 # config/services.yaml services : foo : class : App\SomeNamespace\SomeClass bar : class : App\AnotherNamespace\SomeDifferentClass App\SomeNamespace\SomeService : calls : - method : setSomeItems arguments : - '@foo' - '@bar'

You'll see the following error when running the lint:container command:

1 2 3 Invalid definition for service "App\SomeNamespace\SomeService": argument 2 of "App\SomeNamespace\SomeService::setSomeItems" accepts "App\SomeNamespace\SomeClass", "App\AnotherNamespace\SomeDifferentClass" passed.

If you are using a continuous integration service, consider adding this new command to the list of linters executed on each build. Check out this link for an example of how we do that for the Symfony Demo application.