8

Normally I would just inject dependancies via the constructor, but it gets to be very verbose when the parent class has dependancies and have to pass them through all the children.

The alternative is to use $this->dependancy = App::make('Dependancy') in the parent class alone. Then both the parent and child constructors can be empty. Is there any downside to doing it this way?

2 Answers 2

6

There is a downside to your approach, doing what you propose will make your application less testable.

What I mean is that if you try to write a unit test for the parent class you will no longer be testing that parent class in isolation. Your test now also depends on the results from the dependency declared inside the parent class.

If you pass this dependency in through constructor injection (or any type of injection) you have control over the dependency and can mock/stub the output from it and better test your parent class in isolation.

Sign up to request clarification or add additional context in comments.

4 Comments

thanks for your answer. is there any solution to my problem then of having to pass all the parent class dependancies via the children. I have a BaseConroller which has dependancies, and I call that BaseController from my ChildController. At present I have to type hint the ChildController with all the classes, then pass them through to the BaseController when calling parent::__construct($dep1, $dep2)
Would you mind updating your question to include some code illustrating your question?
I don't know what the situation was in 2014, but in 2020 this answer is actually incorrect. In your tests you can simply use App::shouldReceive('make')->with('Dependancy')->andReturn(/** your mock */); which I believe is even simplier.
The whole point of the container is to invert control (IoC), and one of the reasons for this is to facilitate easier, less complicated testing. OP's question is what's the difference between injecting dependencies (which still come from the container!) and resolving them from the container directly. There is no functional difference but practically there are differences, ie. methods used, particularly when mocking dependencies in tests. The real answer to the question, is yes, lots of injected dependencies make controller methods' signatures unwieldily so resolving can help clean things up.
3

First of all there is no downside to use App::make('...') or app('...') but if you use type hinting in the constructor then you don't need to inject the dependencies manually. For example, if you have something like this:

class SomeController extends BaseController {

    protected $otherClass = null;

    public function __construct(SomeOtherClass $otherClass)
    {
        $this->otherClass = $otherClass;
    }
}

Now, if you use SomeController class then Laravel will automatically inject the SomeOtherClass into the SomeController class and if your SomeOtherClass has it's own dependencies then Laravel will inject those as well if they are type hinted. So, you may use Dependency Injection in constructor over App::make(...)/app(...) and it would be better if you use Interface to type hint instead of concrete class. It's been said, program over interface not implementation (concrete class).

Generally speaking, there is one thing in dependency injection technique and it is that, while you compose a class with other objects, then it may look complex. Actually, dependency injection is a way to compose a class by mixing other objects at runtime through constructor method (composition over inheriting) but sometimes it may look complex to find out the object's relationship to each other if there are so many dependencies. Ultimately it's a good design pattern which gives us a way to decouple the objects from each other and you need to chose wisely when to use it.

Update: Actually, in Laravel when you type hint a dependency in the constructor method, the framework automatically injects the dependencies by reading the type of it's dependent object and behind the scene, Laravel uses the App::make(...) method. So, if you don't use dependency injection then you just need to manually use the App::make(...), that's all. In both cases, the App::make() is being used, either automatically by the framework or by the developer. So, use App::make() without any hesitation, it's safe and a better approach to decouple the dependencies from each other.

In other words, if you type hint the dependencies in the constructor method then Laravel will use App::make(...) to automatically inject them but if you don't type hint then You need to manually inject them and in this case you'll use App::make() instead of framework, that's it. For automatic resolving of dependencies, you need to type hint your dependencies but if you manually inject your dependencies then you don't need to type hint them and without type hint, Laravel can't inject any dependencies automatically and it makes sense. Btw, I'm not thinking about testing tho.

8 Comments

I don't want to type hint in the constructor because my class is extending another class, and I'd have to type hint both the child and parent. it gets verbose when i'm injecting 4 classes.
Which one is extending which class ?
As I already mentioned that, Laravel is able to resolve nested dependencies if you type hinted them as well.
my BaseController has multiple dependancies.
If you type hint those dependencies in your BaseController then you don't need to pass them manually. Laravel will automatically inject those dependencies when making the instance of your Controllers.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.