Typed properties, introduced in PHP 7.4, are one of the most important features added by PHP in years. In Symfony 5.1 we're implementing new features based on them, such as extracting typed properties info using the PropertyInfo component.
Consider this example using typed properties:
1 2 3 4 5 6 7 8 9 10 11 12 13
use Twig\Environment;
class SomeServiceClass
{
/** @required */
public Environment $twig;
public function someMethod()
{
$this->twig->render('...');
// ...
}
}
In previous Symfony versions, this example wouldn't work because Twig service
is not properly injected. In Symfony 5.1, this example will work as expected.
The reason is that Symfony 5.1 autowires all public properties that are typed
with classes related to services and which include the @required
annotation.
Some things to consider:
- Only public properties are autowired; protected and private properties will never be autowired to avoid any confusing behavior;
- This is in practice equivalent to setter injection, which has drawbacks and it should be used only in very specific scenarios.
This new feature is just one of the many tools that Symfony gives you to automate the configuration of how services/objects should be created. If it doesn't fit your way of developing applications, it's OK to keep using the traditional service injection based on constructors and private properties.
Isn't this against the Encapsulation pattern? https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)
What about public static properties, will these also be autowired?
@Thomas Manual wiring like that was already possible. Because of the property types, it can now be wired automatically.
@Martin I'd guess it's possible, though I don't think doing so is a very good idea as it influences the "state" of other instances of your service.
@Thomas Schulz has a point here. I'm afraid that adding such feature restricted to public properties only may convince people learning PHP and Symfony to use public properties everywhere cause they may expect Symfony's documentation to follow best practices.
@Nikodem Ośmiałowski don't worry about documentation presenting this feature in every possible place. Note the first bullet point in the article: "This is in practice equivalent to setter injection, which has drawbacks and it should be used only in very specific scenarios.". We don't recommend anyone using setter injection in the docs, so we won't also rewrite all examples to use autowired public properties.
@Wouter, then why Symfony is adding a feature which is obviously a bad practice? Any feature requires support, it adds up to the code base. This effort could have been spent on many other really important Symfony issues.
This builds on the idea that contributions are following a master plan. That's not the case: ppl contribute what they want.
It's as a bad practice as using setters, yet setters are just the right solution to some problems. Same here: it's not Symfony's role to decide what should be possible or not. The DI container is here to wire code that ppl wrote, this is one possible. That's all folks...
@Nicolas, I meant the future effort to support the feature, not the effort to add it. I should have written "this effort could be spent", my fault.
I understand your second point.
Awesome, thanks for this! For objecting like everyone else, it's not better to call the annotation @Inject.
I think this is really bad practice, I wish you that Symfony team consider reverting such feature before it's too late
I would have liked to have seen this supporting private/protected properties thus eliminating the need for boilerplate setter functions. Curious to see how doing so would cause "confusion". I just can't see the value of having public dependencies.
i can't figure out what is the advantage over the constructor injection
Funny thing to read this, as my team and I thought about it not later than 2 weeks. I see this as a BIG improvement in readability but I can understand why people are concerned about "encapsulation". In the end, we always use a class property to store the injected service but it can quickly be a mess if the services are mixed with other properties.
Do you think that it is possible to enable it from the config, or enable a hybrid version where only annotated property are autowired, an annotation like "@Autowire" for instance ?
Amazing!