Skip to content

[DependencyInjection] Autowire public typed properties #34769

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 7, 2019
Merged

[DependencyInjection] Autowire public typed properties #34769

merged 1 commit into from
Dec 7, 2019

Conversation

Plopix
Copy link
Contributor

@Plopix Plopix commented Dec 2, 2019

Q A
Branch? master
Bug fix? no
New feature? yes
Deprecations? no
License MIT

Description

This PR adds the Autowiring of public typed properties in PHP 7.4.
It is only on "public" properties.

It could let people think that services are better injected in "public".
I don't know what to think about it, you?

How about "private" properties - further thinking

Even if I think that it would be awesome to be able to inject in "private" properties, we discussed it with @nicolas-grekas, and I agree Symfony should not break any standard logic. If the property is private then it is private the DI cannot touch it.

But that could/would remove a lot of boilerplate, and if it is declarative, that might still be something to do.
Maybe we could introduce a new annotation for injection in "private": @requiredPrivated ?

Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are some comments. Next step is making AutowirePass able to resolve these references for named autowiring aliases.

@nicolas-grekas nicolas-grekas added this to the next milestone Dec 3, 2019
@michaljusiega
Copy link
Contributor

Maybe @autowired annotation will be better instead of @required just like in Spring?

@nicolas-grekas
Copy link
Member

nicolas-grekas commented Dec 3, 2019

Maybe @autowired annotation will be better instead of @required just like in Spring?

there is a fundamental difference between them: @autowired is a piece of configuration of the DIC. @required is a declarative annotation stating that a property (or a method) is part of the instantiation stage of a class. The latter is useful info to the reader, human or computer, and is totally independent of the DIC logic. It happens that the autowiring system knows about it and can wire them when there is no preexisting configuration for that property/method. @autowired being configuration, it's mostly targeting the DIC logic without adding any useful piece of semantics to the code: it's just configuration in the code - it could be anywhere else without reducing the semantics of said code (e.g. in Yaml). But e.g. what should happen when a class is loaded as a service by some yaml, and the annotation conflicts with that yaml config? That's part of the reason why configuration via annotations is a no go.

So, definitely not @autowired as it doesn't convey the meaning we want here.

@michaljusiega
Copy link
Contributor

@nicolas-grekas Thank you for the explanation :)

@Plopix
Copy link
Contributor Author

Plopix commented Dec 3, 2019

also, we might have detected a bug. I was trying to do:

    _defaults:
        autowire: true      
        autoconfigure: true
        bind:
         MyInterface $service: '@App\MySuperServiceA'
class MySuperServiceB {

  /**
   * @required
   */
  public MyInterface $service;

but I get a

In ResolveBindingsPass.php line 82:
  A binding is configured for an argument of type "PlopInterface" named "$service" under "_defaults" in file "/private/tmp/testinjection/config/services.yaml
  ", but no corresponding argument has been found. It may be unused and should be removed, or it may have a typo.

@nicolas-grekas nicolas-grekas changed the title [Dependency Injection] Autowire public typed properties [DependencyInjection] Autowire public typed properties Dec 3, 2019
@nicolas-grekas
Copy link
Member

also, we might have detected a bug. [...]

good catch, fixed in #34776

Copy link
Member

@dunglas dunglas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good replacement for setter injection, but keep in mind to avoid using setter injection (and property injection) as much as possible :)

fabpot added a commit that referenced this pull request Dec 4, 2019
…las-grekas)

This PR was merged into the 4.3 branch.

Discussion
----------

[DI] fix resolving bindings for named TypedReference

| Q             | A
| ------------- | ---
| Branch?       | 4.3
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | -
| License       | MIT
| Doc PR        | -

As spotted in #34769 (comment)

Commits
-------

62c227e [DI] fix resolving bindings for named TypedReference
@fabpot
Copy link
Member

fabpot commented Dec 7, 2019

Thank you @Plopix.

fabpot added a commit that referenced this pull request Dec 7, 2019
… (Plopix)

This PR was merged into the 5.1-dev branch.

Discussion
----------

[DependencyInjection] Autowire public typed properties

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| License       | MIT

### Description

This PR adds the Autowiring of **public typed properties** in PHP 7.4.
It is only on "public" properties.

It could let people think that services are better injected in "public".
I don't know what to think about it, you?

### How about "private" properties - further thinking

Even if I think that it would be awesome to be able to inject in "private" properties, we discussed it with @nicolas-grekas, and I agree Symfony should not break any standard logic. If the property is private then it is private the DI cannot touch it.

But that could/would remove a lot of boilerplate, and if it is declarative, that might still be something to do.
Maybe we could introduce a new annotation for injection in "private": `@requiredPrivated` ?

Commits
-------

cad7fbb [DI] Autowire public typed properties
@fabpot fabpot merged commit cad7fbb into symfony:master Dec 7, 2019
@matks
Copy link

matks commented Dec 12, 2019

Hi, I'm sorry for providing this very late feedback, I saw this new feature through the tweet https://twitter.com/Pehapkari/status/1205145395845840896 and, following multiple other twitter users, I am quite afraid of the consequences of this feature.

This feature has obvious benefits in term of avoiding writing boilerplate code and, as stated by @dunglas, can quite nicely avoid the use for setter injections.

What I am afraid of is that this feature looks like a step forward into "magic" behaviors happening in Symfony. I think you can guess what I mean: by writing a php comment, writing some "text" then some php functions will automatically called by Symfony to make things happen.

The disadvantages of these behaviors are:

  • when bugs arise, they are a lot harder to analyze as it's hard to find what function is called by which class, the stack trace is harder to explore
  • in combinations with other similar behaviors annotation-driven (like serializer annotations or doctrine annotations) I'm afraid it could lead to bugs very complex to diagnose and handle
  • in the wrong hands, like a junior developer not aware of the mechanism behind, this could lead people to write some crazy code (for example someone trying to customize the injection but failing to understand that he should not use it in its case, then trying to perform some later processing in the __construct() for example)
  • if used by junior developers it could provide them a false idea of how php objects are built in Symfony as they might not question what this little "@required" string actually does ; then ampering their ability to learn the language and the framework

I am aware these arguments are the classic arguments against "magic" behaviors, and could be raised against Serializer annotations, Doctrine annotations, services autowiring ...
So maybe I am paranoid 😅. It's just that I have seen projects using magic behaviors in a very wrong manner leading to huge technical debt and very bad maintainability. So I just share my thoughts here, leaving you to decide what to do about it 😉

Have a nice day

@stloyd
Copy link
Contributor

stloyd commented Dec 12, 2019

I would say that this is quite big feature, really quickly (5 days...) being accepted & merged, while it's impact is way bigger than it looks like IMHO.

Good read why not using such approach was written few years ago already: http://olivergierke.de/2013/11/why-field-injection-is-evil/

I'm not totally against this, neither approve it... but it looks like the review process was kinda too quick to allow community to see it...

@matks
Copy link

matks commented Dec 13, 2019

An additional piece of read provided to me by @toutantic https://www.petrikainulainen.net/software-development/design/why-i-changed-my-mind-about-field-injection/ that explains a lot better than me the possible negative outcomes of this approach

@nicolas-grekas
Copy link
Member

Thanks for the comments but this PR didn't introduce property injection. Actually this kind of injection exists since before Symfony 2.0.0 was tagged.

@matks
Copy link

matks commented Dec 13, 2019

Thanks for the comments but this PR didn't introduce property injection. Actually this kind of injection exists since before Symfony 2.0.0 was tagged.

Are you referring to Property Injection ? Then you're right, but this is only a mismatch of vocabulary.

If I am not wrong, Symfony already had "Property Injection" (as referenced above) and this PR introduces "Autowired Property Injection". The 2 blog articles (which refer to Java it seems) we mentioned talk about "Property Injection" but if you read them, what they refer as "Property Injection" is actually what Symfony refers as "Autowired Property Injection".

So Autowired Property Injection is the mechanism that we are worried about.

@nicolas-grekas
Copy link
Member

nicolas-grekas commented Dec 13, 2019

I'm not sure at all that others talk specifically about what this PR provides. Looking at the Twitter thread, ppl rant about property injection itself. They don't need to change their mind, this PR is about something else.

About the article you linked now that I read it, there is a critical difference with the feature provided here: the code examples all use private properties for field injection. This is just plain wrong.

To @Plopix that asks in the PR description above about How about "private" properties - further thinking, the answer is a big all caps NO WAY. The article explains it well.

The DI container of Symfony is about automating the creation of objects saving us from writing the wiring code by hand. There is a decisive implicit requirement in this statement: you should be able to write the wiring by hand using plain PHP code. That excludes using protected or private properties or methods.

So, nothing to see here to me: the authors write their classes, then, afterward, we wire them together. The DI container is only about that. PHP 7.4 provides type annotations on properties. The DI container has to autowire them now that it has all the required information. It's a matter of feature completeness, nothing else.

@nicolas-grekas nicolas-grekas modified the milestones: next, 5.1 May 4, 2020
@fabpot fabpot mentioned this pull request May 5, 2020
xabbuh added a commit to symfony/symfony-docs that referenced this pull request Aug 3, 2020
This PR was merged into the 5.1 branch.

Discussion
----------

Add public typed properties autowiring

https://symfony.com/blog/new-in-symfony-5-1-autowire-public-typed-properties and implemented in symfony/symfony#34769

Commits
-------

3451964 Add public typed properties autowiring
@derrabus derrabus mentioned this pull request Nov 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants