简体   繁体   中英

how to implement dependency injection container and dependency injection

I want to know how to implement a dependency injection container using php(for study). I get the concept of dependency injection and i can implement it but I can only factor out until controllers of php frameworks.

Meaning the whole instantiation, injections, and etc happen in the controller. Like

       class SampleController{

       public function action1(){
            $sample_object = new ObjectToInject();
            $dependent_object = new DependentObject($sample_object);
            $dependent_object->doSomething();
            ...
            etc
       }


      }

Now what I'm saying is the controller gets bloated if the logic gets more complicated. I know that my controller gets bloated, doesn't that mean that it is still not so maintainable?

Questions:

  1. Is my assumption correct that the controller now have all the logic?
  2. Then what is the use of a Dependency Injection Container? and is this the same as what he said as bootstrapper in this article ?
  3. Kindly explain what Symfony2 Dependency Injection Containers do.
  4. Please give me a concrete example of Dependency Injection Container using php.
  5. Am I correct that in unit testing, only dependent classes are to be tested and independent classes does not need to be tested.

Kindly correct me if me questions are vague. Thanks

This is a really loaded question. To quickly answer your points:

(1) No. That is not correct. While you have to do your wiring somewhere, it should not be in your controllers. Your controllers should receive only the fully built objects they need to do their jobs. Don't give them more than they need. Example:

example

class UserController 
{
    public function __construct(UserRepository $UserRepository)
    {
        $this->UserRepository = $UserRepository;
    }

    public function showUser($id)
    {
        $User = $this->UserRepository->find($id);
    }
}

Note that UserController only has UserRepository as a dependency? UserRepository meanwhile might look like this:

class UserRepository
{
    protected $registry = array();

    public function __construct(UserFactory $UserFactory, UserMapper $UserMapper)
    {
        $this->UserFactory = $UserFactory;
        $this->UserMapper = $UserMapper;
    }

    public function find($id)
    {
        if (isset($this->registry[$id]) {
            return $this->registery[$id];
        }

        $User = $this->UserMapper>find($id);
        $this->registry[$User->id] = $User;
        return $User;
    }

    public function findOrNew($id)
    {
        if (!$User = $this->UserMapper->find($id)) {
            $User = $this->UserFactory->make(array('id' => $id));
        }

        return $User;
    }
}

Your UserController should have no knowledge of the UserFactory or the UserMapper objects if it does not need them directly. Further, your UserRepository should not know about the DataAccessLayer that gets injected into UserMapper . UserMapper also doesn't need to know that DataAccessLayer is relying on a PDOConnection object instead of something else.

(2) The use of a container is to do what you SHOULDN'T be doing in your controllers: wiring up all of your dependencies. The simplest, easiest way to understand what a DI Container is and how it works is to download and use Pimple. It's a really simple, straight-forward DI container and it's well documented: https://github.com/fabpot/Pimple

(3) That's a big topic. Symfony's is a more advanced version of Pimple. I suggest learning Pimple and then reading through the documentation for Symfony and seeing the examples they use. Also check out Laravel's, or even PHP-DI https://github.com/mnapoli/PHP-DI

(4) As before see Pimple: https://github.com/fabpot/Pimple

(5) You should strive to test all of your code logic as long as there is something to test. Presumably, each method/function/class in your application does something , so you should test that it's doing what it should do. What you don't have to do, is test that any of its dependencies are doing what they should do, because you are presumably testing those. You trust that the data being passed into one class or method has been tested, and then you test only what the new class/method is meant to be doing.

But again, I highly recommend learning on Pimple, and then trying out something like PHP-DI to see how auto-reflection and auto-resolving dependencies works. The best way to do it is just immerse yourself in a variety of containers and play around with them.

Instantiating dependencies is not "logic", it's just configuration.

AmgLauncher wrote a great answer, I want to provide a simpler one: controllers are no different than services. You should use dependency injection on controllers, just like for services.

Here is the problem: Symfony doesn't encourage that (through their documentation at least). Don't blindly follow Symfony's DIC documentation.

So in the end, the question is: but what/who will construct my controller if it has dependencies?

That's the job of the container. The container will build your controller and all your services. The catch is that some frameworks don't work that way. In Symfony 2, there's an option for that: Controllers as services .

If you were to use Pimple, you would have to write all the code that creates all your controllers. That's useless/boring code. Pimple is not really suited for that.

As AgmLauncher suggested, have also a look at PHP-DI , and for example this guide about how to write controllers . I recommend also you to read this simple introduction to What is a DI container and how it works . (disclaimer: I'm the maintainer of PHP-DI)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM