Your question is the exact reason why dependency injection - when everything is done correctly (not in the way the most popular frameworks are used) - is considered a preface to code testing.
To understand why, let's see how "helper functions" and class-oriented programming make testing your controllers difficult.
class Helpers { public static function myHelper() { return 42; } } class MyController { public function doSomething() { return Helpers::myHelper() + 100; } }
The whole unit of unit testing is to verify that the "units" of code work in isolation. If you cannot isolate functionality, your tests are pointless because their results may be corrupted by the behavior of other involved code. This can lead to the fact that statisticians call errors of type I and type II: basically this means that you can get test results that can harm you.
In the above code, the helper cannot easily make fun of it to determine that MyController::doSomething works in complete isolation from external influences. Why not? Since we cannot βmake fun ofβ the behavior of the helper method, to ensure that our doSomething method actually adds 100 to the helper result. We adhere to the exact behavior of the helper (return 42). This is a problem that completely excludes the correct orientation of the object and inversion of control. Consider an example of how:
If MyController requests these dependencies instead of using a static helper function, it becomes trivial to mock external influences. Consider:
interface AnswerMachine { public function getAnswer(); } class UltimateAnswerer implements AnswerMachine { public function getAnswer() { return 42; } } class MyController { private $answerer; public function __construct(AnswerMachine $answerer) { $this->answerer = $answerer; } public function doSomething() { return $this->answerer->getAnswer() + 100; } }
Now itβs trivial to simply verify that MyController::doSomething really adds 100 to what is returned from the answering machine:
// test file class StubAnswerer implements AnswerMachine { public function getAnswer() { return 50; } } $stubAnswer = new StubAnswerer(); $testController = new MyController($stubAnswerer); assert($testController->doSomething() === 150);
This example also shows how the proper use of interfaces in your code can greatly simplify the testing process. Test frameworks such as PHPUnit mock interface definitions very easily in order to accomplish exactly what you want to test the isolated functionality of code blocks.
So, I hope these very simple examples demonstrate how powerful dependency injection is when it comes to testing your code. But more importantly, I hope they demonstrate why you should be wary if your selection frames use static (just another name for global ones), one-stop and helper functions.