3fa8a0571d
This PR was squashed before being merged into the 3.3-dev branch (closes #21763). Discussion ---------- [DI] Replace wildcard-based methods autowiring by `@required` annotation | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no (affects things that are only on master) | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - While playing a bit with new features in master around DI configuration, several people around me got bitten by wildcard-based autowiring. The typical example is adding `autowire: [set*]` in `_defaults`: use that on `resource: ../src/Command/` PSR4-based loading and boom, `setApplication` and `setHelperSet` will now be wrongly called. You could tell me "of course, don't to that" - but being bitten so early on a master-only feature makes me really unconfident that this will be easy enough for people after the release. If wildcard-based autowiring is removed, then I don't see anymore the need for allowing arrays as in `autowire: [setFoo,getBar]`. Moreover, this array syntax has a core DX issue: it's a dead end as far as the learning curve is concerned. You learn it, then when becoming a more advanced dev, someone teaches you that you'd better use another syntax: explicit wiring. And in fact, we don't need it at all, because something else already exists: just declare a method call, but don't define its arguments. If `autowire: true` is set, then the AutowiringPass already fills in the holes. There is only one tweak required to make this work: don't autowire optional arguments for method calls - or that'd be a BC break. To my PoV that's even better: this makes autowiring fit a "do the minimum to make it work" strategy. A really good one to me. But there is still an issue: wildcard-based autowiring fits a need. Namely, it allows one to define a convention (eg. `'set*'`), and have all such methods that follow the convention be autowired. To me, this looks like doing it reverse (the DI config should adapt to the code, not reverse). So, to fill this need, let the declaration be in the source: just use an annotation! This PR adds support for the `@required` annotation, borrowed from the Spring framework: https://www.tutorialspoint.com/spring/spring_required_annotation.htm Using the annotation is totally optional of course. If you do, *and if autowiring is on*, then it'll be autowired. If you don't, nothing changes: do manual wiring. Even when not using autowiring, the annotation is still a nice hint for the consumer of your classes: it tells the reader that this method needs to be called for correct instantiation - thus lowering one drawback of setter injection (discoverability). The implementation of the annotation parsing is done using a few regexp (no dep on any complex parser) - and works with inheritance, by leveraging the `@inheritdoc` tag (the default behavior being to *not* inherit anything from parent methods). All in all, looking at the diff stats, it makes everything simpler. Good sign, isn't it? Commits ------- |
||
---|---|---|
.. | ||
bad_calls.yml | ||
bad_decorates.yml | ||
bad_format.yml | ||
bad_import.yml | ||
bad_imports.yml | ||
bad_parameters.yml | ||
bad_service.yml | ||
bad_services.yml | ||
bad_types1.yml | ||
bad_types2.yml | ||
badtag1.yml | ||
badtag2.yml | ||
badtag3.yml | ||
class_from_id.yml | ||
legacy_invalid_alias_definition.yml | ||
legacy_invalid_definition.yml | ||
nonvalid1.yml | ||
nonvalid2.yml | ||
services1.yml | ||
services2.yml | ||
services3.yml | ||
services4_bad_import.yml | ||
services4.yml | ||
services6.yml | ||
services7.yml | ||
services8.yml | ||
services9.yml | ||
services10.yml | ||
services11.yml | ||
services13.yml | ||
services14.yml | ||
services21.yml | ||
services22.yml | ||
services23.yml | ||
services24.yml | ||
services26.yml | ||
services28.yml | ||
services31_invalid_tags.yml | ||
services31.yml | ||
services_configurator_short_syntax.yml | ||
services_instanceof.yml | ||
services_locator_argument.yml | ||
services_named_args.yml | ||
services_prototype.yml | ||
services_underscore.yml | ||
tag_name_empty_string.yml | ||
tag_name_no_string.yml | ||
tag_name_only.yml | ||
yaml_with_wrong_ext.ini |