Search code examples
phpsymfonydependency-injectioninversion-of-controlsymfony-2.5

Many dependencies in service


I have trouble with dependencies in my application in service layer.

I have following class:

   <?php

class UserService{

    private $userRepository;
    private $vocationService;
    private $roleService;

    public function __construct(UserRepository $userRepository, VocationService $vocationService, RoleService $roleService)
    {
        $this->userRepository = $userRepository;
        $this->vocationService = $vocationService;
        $this->roleService = $roleService;
    }


} 

There are only three dependencies which I'm injecting. Assume, I want to add next dependency, for example: NextService. My constructor will grow again.

What if I wanted to pass more dependencies within constructor ?

Maybe should I solve this problem by passing IoC container and then get desirable class? Here is an example:

<?php

class UserService{

    private $userRepository;
    private $vocationService;
    private $roleService;

    public function __construct(ContainerInterface $container)
    {
        $this->userRepository = $container->get('userRepo');
        $this->vocationService = $container->get('vocService');
        $this->roleService = $container->get('roleService');
    }

} 

But now my UserService class depends on IoC container which I'm injecting.

How to solve a problem following good practices?

Regards, Adam


Solution

  • Injecting the container as a dependency to your service is considered as a bad practice for multiple reasons. I think the main point here is to figure out why and then try to understand the problem that leads you to think about "injecting the container" as a possible solution and how to solve this problem.

    In object oriented programming, it's important to clearly define the relations between objects. When you're looking at a given object dependencies, it should be intuitive to understand how the object behaves and what are the other objects it relies on by looking at its public API.

    It's also a bad idea to let your object rely on a dependency resolver, In the example you shared your object can't live without the container which is provided by the DI component. If you want to use that object elsewhere, in an application that uses another framework for example, you'll then have to rethink the way your object get its dependencies and refactor it.

    The main problem here is to understand why your service needs all these dependencies,

    In object-oriented programming, the single responsibility principle states that every context (class, function, variable, etc.) should define a single responsibility, and that responsibility should be entirely encapsulated by the context. All its services should be narrowly aligned with that responsibility. Source: Wikipedia

    Based on this definition, I think you should split your UserService into services that handle only one responsability each.

    • A service that fetch users and save them to your dababase for example
    • Another service that manages roles for example
    • ... and so on