Back in Symfony 5.3 (released in May 2021), we introduced config builder classes as a fluent PHP interface for configuring Symfony applications. These classes were generated dynamically depending on which bundles were installed and made it possible to configure your app like this:
1 2 3 4 5 6 7 8 9 10 11 12
// config/packages/security.php
use Symfony\Config\SecurityConfig;
return static function (SecurityConfig $security) {
$security->firewall('main')
->pattern('^/*')
->lazy(true)
->anonymous();
$security
->accessControl(['path' => '^/admin', 'roles' => 'ROLE_ADMIN']);
};
In Symfony 7.4, as part of the broader effort to modernize configuration formats (and since we're deprecating the XML configuration format), we're also deprecating the config builder classes and the fluent PHP configuration.
The main reason is technical: fluent configuration is not flexible enough and must match a single canonical interpretation of the semantic config tree. It also makes automatic configuration updates (via Symfony recipes) significantly harder.
So what's replacing the fluent format? We're introducing a new array-based PHP configuration format. The previous example now becomes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
// config/packages/security.php
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
return App::config([
'security' => [
// ...
'firewalls' => [
'main' => [
'pattern' => '^/*',
'lazy' => true,
'anonymous' => true,
],
],
'access_control' => [
['path' => '^/admin', 'roles' => 'ROLE_ADMIN'],
],
]
]);
If at first sight this looks like "just arrays", you're not wrong. It's simple, compact, and very familiar: much like YAML, but directly in PHP. However, there is a lot more to it.
To make this new format truly shine, Symfony now defines array shapes for all configuration. These are PHP metadata definitions that tools like PhpStorm, PHPStan, Psalm, and others can read and process. This means:
- full autocompletion
- static analysis
- type validation
- instant discoverability of every config option
As you can see, these are not ordinary arrays. They combine the readability of YAML with the tooling advantages of native PHP.
These shapes are generated dynamically based on the bundles installed in your
application. The generated file is called reference.php and is stored in the
config/ directory. You should commit it to your repository and optionally add
a new entry in the autoload section of composer.json (for example,
"classmap": ["config/"]).
We’re not ready yet to make this new format the recommended one. YAML still offers many advantages. However, this update opens the door to using PHP as a first-class configuration format in the future. The new approach is concise, expressive, easy to maintain, well-supported by modern tools, and benefits from the full power of PHP. What’s still missing? Not all static analyzers and IDEs fully support complex array shapes yet, Symfony Flex currently understands YAML only, and a few other pieces still need refinement before this vision can become reality. Even so, this marks an exciting step toward a more unified, powerful, and developer-friendly configuration experience in Symfony.
Great step in preparation of basic generics, hopefully making it to PHP in 8.6
For environment tests, use the
when@{env}syntax:Like it. Think we can adopt https://github.com/schranz-php-recipes/ to convert to the new syntax. How does it look like if there is not only bundle configuration but also parameter and service configuration. Did that Syntax also change?
I must be missing something because I don't understand how the config/reference.php file is generated.
What a pain this config/reference.php file is, it's constantly being modified and appears in all my commits. Furthermore, the syntax is broken if a config file contains
/*, such as**/*.graphqlin my case.I have "dump(" on my git_blacklist, but I get now "dump(" on the reference.php file. Bit quiet annoying
Is there a particular reason to commit reference.php file instead of ignoring it? Currently this file doesn't bring any visible benefits for us, but adds a little bit of hustle to maintain it instead.
Not a fan of shifting the onus on the tooling. PHP already has a way of describing contracts: classes. Config builder was my absolute favorite feature of Symfony. It was easy to read and reason about. I dislike array-based contracts with a passion. Not sure that it's a step in the right direction. Why not keep both?
Can you elaborate on this?
Question... how is this better than YAML? We just lost all of the strong typing advantages of the PHP objects, it seems.
What is the actual suggested best practice now, PHP or YAML? The PHP config examples on the latets 8.0 version of the documentation all shows the now deprecated way of configuring via PHP objects.
the IDE type hinting on available keys is absolutely disasterous