首页 > 解决方案 > Symfony: what does autowiring solve?

问题描述

Correct me if I'm wrong - Symfony autowiring allows a programmer to automagically get an instance of a Service as an argument to a function by typehinting that argument.

So instead of typing (for example)

public function dostuff() {
  $stuff = StuffGenerator::getInstance();
  $stuff->do();
}

I can now type

public function dostuff(StuffGenerator $stuff) {
  $stuff->do();
}

and then just trust $stuff is good. Is that all ?

I still prefer the first method. I am inclined to avoid autowiring as much as possible. I've been reading up on it, but sofar nothing has convinced me handing over my app logic to a higher power, which I then have to configure, or worse, just trust it, is a good idea.

For one thing, it makes your code less portable.

What am I missing ? Are there situations where I can not avoid autowiring, because it solves some unique problem I am not aware of ?

标签: symfonydependency-injectionautowired

解决方案


These sorts of questions are usually not a good fit for stackoverflow but "what does autowiring solve" can be answered.

First thing to realize is that the example in the question has nothing to do with autowiring or dependency injection in general.

public function dostuff(StuffGenerator $stuff) {
  $stuff->do();
}

The implication of the above example is that some mysterious force is injecting stuff directly into methods which in turn immediately acts upon them. Well no. Autowire does not do this. And I certainly would not want methods being called with arguments from who knows where.

So lets rewrite the example:

class MyClass {
    private $stuff;
    public function __construct(StuffGenerator $stuff) {
        $this->stuff = $stuff;
    }
    public function doStuff() {
        $this->stuff->do();
    }
}

In almost all cases, dependencies are injected into constructors and then stored as member variables. Nothing mysterious going on in the rest of the class. You can argue about injecting $stuff vs having the constructor accessing $stuff from say a singleton. I won't get into that argument here as it is basically off topic with respect to autowire.

For the above MyClass example to work using the Symfony container requires that the container be aware of what dependencies are needed. Back in the old pre-autowire days (prior to 3.1 or so), a developer had to manually define each service. Something like:

# app/config/services.yml
services:
    app.stuff_generator:
        class App\StuffGenerator
    app.myclass:
        class: App\MyClass
            arguments:
                - '@app.stuff_generator'

Not hard to do but as the number of services grew so did the size of the services file. Just as a trip down memory lane, here is one of about 6 different service definition files for one of my S2.x apps. It was actually kind of nice having all the definitions in one place. Made it easier to see how things were wired up. But it definitely got tedious.

So now we come to the actual question. Assuming that you buy into the notion of using dependency injection in combination with a service container, then autowire simplifies the process of defining your services in your container. For the MyClass example, no manual service configuration is needed at all assuming there is only one StuffGenerator instance floating around. And of course you will run into things like scaler dependencies that require manual definitions. But still, hundreds and hundreds of lines of configuration can be reduced to perhaps a few dozen.

And that is what autowire solves.


推荐阅读