What it is the best way to implement a dependency injection, this way:
new App\Controllers\HomeController();
Class HomeController
use App\Views\HomeView;
class HomeController {
private $view;
public function __construct() {
$this->view = new HomeView();
or this way:
new App\Controllers\HomeController(new App\Views\HomeView());
Dependency injections is usually (if not always) done via a IoC (Inversion of control) - container. The container, or rather it's dependency injection logic takes care of creating the objects and through some magic fetches all the parameters expected to be added and creates them, also from the containers dependency injection logic.
What you are doing is rather just creating new objects. You could do that either way you wish, but personally I would probably pass the view through the constructor.
If you wish to read more about dependency injection and containers, id refer to the wiki entry about it.
You can also take a look at one of my naive implementations of a dependency container using php reflections here if you wish!
Samples you've provided reflect totally different approaches (I've left class naming same as you have):
// App/Controllers/HomeController.php
use App\Views\HomeView;
class HomeController {
private $view;
public function __construct() {
$this->view = new HomeView();
}
}
This is not dependency injection, you create the stuff your class depends on inside the class.
Compare to:
// App/Controllers/HomeController.php
use App\Views\HomeView;
class HomeController {
private $view;
public function __construct(HomeView $view) {
$this->view = $view;
}
}
This is actually dependecy injection: whatever your class needs is created outside of the class and passed to it via constructor (in this particular case).
Some tool (dependency injection container) may or may not be used to manage the dependencies depending on your case.
To get some more details please see the article https://martinfowler.com/articles/injection.html by Martin Fowler and search here on SO - the topic is extensively covered (What is dependency injection?, What is Dependency Injection?, When to use Dependency Injection).
Related
I'm a self-learner, trying to become a good PHP developer and want to fully understand Dependency Injection.
I understand the broad principle, in theory dependency injection makes my classes not have tightly coupled dependencies to other classes.
But I don't understand how this can be fully implemented in practice.
Example using the PHP League Container and an Example Controller:
/***************************************************************************************
* DI Container setup
***************************************************************************************/
$container = new Container();
/***************************************************************************************
* Register Service Providers
***************************************************************************************/
$container->addServiceProvider(new \App\Providers\ConfigProvider);
/***************************************************************************************
* Register Container Class Dependencies
***************************************************************************************/
$container->share('App\Http\Controller')
->withArguments(['config']);
Now in my controller I would receive the injected dependency like this:
class Controller
{
public $config;
function __construct($config)
{
$this->config = $config;
}
function index()
{
$newConfigItem = 'domain.com';
$configDomain = $this->config->setConfig($newConfigItem);
}
}
The Controller is just an example, it could be any class, any type of class like maybe a Serviceprovider, Middleware etc.
This is more a general question regarding the correct handling of dependency injection.
Doesn't using the setConfig() method of the injected Config class creates a new tightly coupled dependency?
Even if I would use the Container to create a new Object, using the container directly in any class just created a dependency to the container method used to register / extend Objects in the Container.
Or do I need an extra layer of PHP classes that somehow wrap my dependencies to use new method names, but even then this extra layer of php classes has then dependencies that need adjusting if I need to switch out libraries/packages/components used.
Where am I going wrong in my thinking?
Doctrine examples usually make use of Doctrine's $entityManager. Hence, whenever I need to do anything in my app with Doctrine, I need to get the entity manager into my code. But how? .... I can inject it into my class, but still I need to create manager somewhere first. I can also make it use PHP's trait which I put into my class to make it Doctrine-enabled.
What I have done in my OOP code is something like this -- I defined a class DoctrineConnector in its own namespace of DoctrineConnector, and inside the class I have a static function getEntityManager. Inside, I read Doctrine configuration, paths, parameters, and create an $entityManager, and then I return it to the caller.
Whenever I need to read or persist something in my Doctrine-unaware code, I do this:
//Pricing.php
use DoctrineConnector\DoctrineConnector;
class Pricing
{
public function getPricing()
{
$entityManager = DoctrineConnector::getEntityManager();
//further Doctrine code to read DB
}
}
DoctrineConnector is now a dependency of Pricing. Obvious answer may be "inject $entityManager into Pricing". But Pricing is called from another class, and that other class is called from another class, etc so I will have to make essentially every class I call be aware of the ORM variable. I want to avoid that.
Is what I currently have just fine or is there a better way?
How ZF2 module system does it
Out of curiosity I looked into how ZF2 manages Doctrine module and from DoctrineORMModule, it uses ServiceLocator pattern to call the inside of controller. So one of the leading framework module systems is not that far off from my implementation.
Singleton Pattern
Adapted from http://www.phptherightway.com/pages/Design-Patterns.html
namespace ABC;
use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;
class DoctrineConnector
{
private static $instance;
public static function getEntityManager()
{
if (null === static::$instance)
{
// Doctrine Config (from Docs)
include 'config/doctrine-config.php';
$config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode);
static::$instance = EntityManager::create($dbParams, $config);
}
return static::$instance;
}
protected function __construct()
{}
private function __clone()
{}
private function __wakeup()
{}
}
//to call
$em = DoctrineConnector::getEntityManager();
//if used later in the code - calls same instance
$em = DoctrineConnector::getEntityManager();
There are a couple of popular ways to get a dependency inside the class.
make the class aware of project environment and let the class locate the dependency (what you did with DoctrineConnector)
use dependency injection (what you are trying to achieve)
In your case, your class now depends on DoctrineConnector and is going to work as long as it can find DoctrineConnector. If you port your class to another project where DoctrineConnector isn't defined, your code isn't going to work.
Normally dependency injection is a decision you make when you start your new project. If you already have a large hierarchy of classes, the injection code will bubble up your hierarchy and there is going to be a lot of work refactoring your code. You might want to think wether you really need that and wether it's going to be worth your time.
If you are writing code for one particular app and have no plans to migrate it to other projects, then you probably don't care about dependency injection. Actually, without injection your code is going to be shorter and easier (faster) to write and understand. On the other hand if you have pieces of code that you want to be independent of the app, you might use dependency injection only for those code segments.
If you haven't injected ORM yet, chances are that the rest of the code is tightly coupled with your app as well, and injecting entityManager isn't going to make your code much more portable.
I've been changing my Controllers and helper classes to use dependency injection, and it seems I've got my helper classes stuck in an infinite loop.
Below is my custom ServiceProvider and the two sample helper classes. As you can see, they inject each other, so they keep going back and forth.
What's the solution to this issue? What mistake do I seem to be making? What can I do so that I can run tests on helper classes like General and Person, while mocking the helper classes that are called from inside of them?
One way that I guess could work is in my ServiceProvider, do the following:
if (isset($appmade->General)) {
// inject the General app that's already instantiated
} else {
$abc = app::make('\Lib\MyOrg\General');
$appmade->General = $abc;
}
Is that the correct way?
// /app/providers/myorg/MyOrgServiceProvider.php
namespace MyOrg\ServiceProvider;
use Illuminate\Support\ServiceProvider;
class MyOrgServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('\Lib\MyOrg\General', function ($app) {
return new \Lib\MyOrg\General(
$app->make('\Lib\MyOrg\Person'),
$app->make('\App\Models\User')
);
});
$this->app->bind('\Lib\MyOrg\Person', function ($app) {
return new \Lib\MyOrg\Person(
$app->make('\Lib\MyOrg\General'),
$app->make('\App\Models\Device')
);
});
}
}
// /app/libraries/myorg/general.php
namespace Lib\MyOrg;
use App\Models\User;
use Lib\MyOrg\Person;
class General
{
protected $model;
protected $class;
public function __construct(Person $personclass, User $user)
{
}
}
// /app/libraries/myorg/person.php
namespace Lib\MyOrg;
use App\Models\Device;
use Lib\MyOrg\General;
class Person
{
protected $model;
protected $class;
public function __construct(General $generalclass, Device $device)
{
}
}
Your helper classes have a case of circular dependency which, when mixed with dependency injection, make them un-instantiable...and there's no good way to get them to work and be easily testable.
There are some hack-y ways to get this to work:
You could use setter injection, injecting the dependency in a
setter method when the helper is used, rather than in the constructor
when it is instantiated. This has many disadvantages, poor
testability being chief among them. (See
http://symfony.com/doc/current/components/dependency_injection/types.html)
In Laravel 5, you could use method injection, particularly if the
dependency is only pertinent to one or two methods. (See
http://mattstauffer.co/blog/laravel-5.0-method-injection)
You could do an existence check like you propose above, or something
with an event listener. But all of this is masking the fact that...
A circular dependency usually indicates that a design change is in order, and is best solved by reconsidering how your classes interact with each other.
If your Person and General classes depend fully on each other, then
it's possible they share a single responsibility and should be
combined into a single class.
If, however, they rely on a subset of each other's functionality,
then there's probably a separate class with its own responsibility
hiding in there somewhere, and then the best solution would be
extract the common functionality into a 3rd class. That way, rather
than having Class A rely on Class B and Class B rely on Class A, both
Classes A and B would instead rely on Class C. You can safely
instantiate them all, and they all remain easily testable.
How can you easily figure out what your new Class C should contain? A great rule of thumb comes from http://misko.hevery.com/2008/08/01/circular-dependency-in-constructors-and-dependency-injection/... "List all of the methods in your class A used by class B, and all the methods in your class B used by class A. The shorter of the two lists is your hidden Class C."
I know some OOP and have read this and that, but am not a hardcore OOP guy and have no formal training and can't rattle off why something should use dependency injection or not, and may not be able to identify all dependencies in a design, hence my question.
Answering a question here on SO (Using a object in methods of other objects) I started to doubt myself. As far as dependencies, is one of these better or worse or both acceptable? Any design limitations?
I have read and understand both but haven't ever come across a comparison. Why would one be better used in a design, etc.
Dependency Injection:
class myClass {
private $db;
public function __construct($db) {
$this->db = $db;
}
}
Registry (maybe also something else):
class myClass {
private $db;
public function __construct() {
$this->db = Registry::get('db');
}
}
It has a lot to do with testability.
In your example, the first (Dependency Injection) is better. The reason it's better is because it accepts db as an argument, which means this is testable, you can use a mock db for testing and test myClass does the right thing with it.
The second example (Registry) is not recommended as not only myClass depends on db, it now also depends on Registry, and the worst part it's that it knows how to get a db. It's too smart, it should be dumb like the first one, dumb things are more testable, smart things are not.
Both methods are possible implementations of dependency injection. Basically dependency injection means to define a way to configure (inject) the classes to be used at runtime in order to make to code more flexible compared to using using hard coded class names and constructors in the code. Dependency injection follows a principle called inversion of control.
This is especially interesting for testing code but can be used in a variety of other scenarios where you want to make an application flexible and maintainable.
While dependency injection mostly is referred to as DI container, it can generally be done using a couple of different methods - which may also coexist. Here comes an (incomplete) list:
using a dependency injection container
pass class dependency as constructor or method args
using a central registry (as long as it is configurable)
using setter methods to set dependencies
using configuration files
user input
...
A dependency injection is required because the object needs certain data to perform its functions correctly.
Dependency Injection can be performed in three different ways:
If Object A depends on object B, then you can create object A while creating object B
You can use some external class ( like Registry, configuration files etc ) to load the dependency objects, This will decouple the creation of your object from the dependency creation. This is called locator pattern where your object creation is dependent upon the locator to load the objects.
You can create the dependency elsewhere and provide it directly to the dependent object. This is called 'manual injection'
Whenever you do any of these, you are already doing dependency injection:
Constructor injection
public class ClassA
{
// declares the dependency in the constructor
public function ClassA( dependency1:String )
{}
}
// and the dependency is created while instantiating the object
var objA:ClassA = new ClassA("Hello World");
Public property injection
public class ClassA
{
// declares the dependency as a public property
public var helloStr:String;
}
var obj1:ClassA = new ClassA();
// dependency is fulfilled by setting a public property after instantiation:
obj1.helloStr = "The Zen Master";
I have a small framework and I coded it like this. I'm not sure if it is called dependency injection or not. I don't know if it is like a design pattern or not. I also don't know and wonder if passing $this as param is a bad practice.
Have a look at this; (Not a working example, just wrote those codes into browser for explanation.)
/* This is engine model */
require_once('Database.class.php');
require_once('Image.class.php');
require_once('Misc.class.php');
require_once('BBCode.class.php');
class FrameWork_Engine_Model
{
public $database, $config, $misc, $bbcode, $controller, $image;
function __construct($config)
{
$this->database = new Database($configParams);
$this->image = new Image($this);
$this->misc = new Misc($this);
$this->bbcode = new BBCode($this);
$this->controller = new Controller($this); //here I call Register controller depending on routing, in this case, register controller.
}
...
}
/* This is register controller */
class Register extends Base_Controller
{
/*I can access anything over Engine Model in my controllers */
$this->engine->database->query(); //I access database model
$this->engine->bbcode->tag('you'); //I access bbcode model
$this->engine->image->sanitizeUploadedFile(); //I access image model
//etc. I can access others models like this.
}
Basically, my controllers can access any models via engine model. I believe dependency injection is all about injecting dependencies into controllers? Like, my register controller needs a database model, routing model, and templating model to work. Here it has everything it depends on. Am I mistaken?
With those said, my questions are:
Is it a valid dependency injection example? If not, what it is? Does it have a name in design patterns?
If it is nothing related to dependency injection, what changes needs to be done to be DI?
Is passing $this parameter on newly created classes is a bad practise? If so, why?
Ps. I know asking 3 questions in a topic isn't something stackoverflow likes, but I don't want to copy paste entire text to ask them.
You are almost there.
Question 1
No, I don't see it as a valid dependency injection example. It resembles a bit a service locator (because you're injecting the entire container into your services and use it to "locate" dependent services).
Question 2
You're making a small confusion between dependency injection and a dependency injection container.
First of, dependency injection means pushing dependencies into an object at runtime instead of creating/pulling them.
To exemplify this:
//hardcoded dependecies
class BadService
{
public function __construct()
{
$this->dep1 = new ConcreteObject1();
$this->dep2 = new ConcreteObject2();
}
}
So in the example above, the BadService makes it imposible to wire other dependencies at runtime because they are already hard pulled into the constructor itself.
//service locator pattern
class AlmostGoodService
{
public function __construct(Container $container)
{
$this->dep1 = $container->getADep1();
$this->dep2 = $container->getADep2();
}
}
In the AlmostGoodService example, we've removed the hard dependencies from the previous example but we are still depending on a specific implementation of our container (meaning that our service is not reusable without providing the implementation for that container). This is the example that matches what you're doing.
//dependecy injection
class GoodService
{
public function __construct($dep1, OptionalInterface $dep2)
{
$this->dep1 = $dep1;
$this->dep2 = $dep2;
}
}
The GoodService service is not concerned with the creation of it's concrete dependencies and can easily be "wired" at runtime with any dependencies that implement the "protocol" of the $dep1 or the OptionalInterface for the $dep2 (therefore the name of Inversion of Control - the underlying concept behind Dependency Injection).
The component that does this wiring is called a dependency injection container.
Now, a dependency injection container, in it's simplest form, is nothing more than an object capable of wiring up your objects at runtime based on some form of configuration.
I said that you are almost there but there are some problems with your implementation:
the wiring should be lazy (you do not want to make all that work in your constructor, as your application would slow down considerably as it grows)
you should not pass the entire container ($this) as a dependency because then you fallback to a weaker inversion of control, namely a service locator. You should instead pass the concrete dependencies to your service constructors
Question 3
There are some cases when you'll find yourself wanting to pass the entire $container as a dependency to a service (namely controllers or lazy service factories), but generally it will be better to stay away from this practice as it will make your services more reusable and easier to test. When you're feeling that your service has too many dependencies, then that it's a good sign that you're service does too much and it's a good time to split it.
Prototype Container Implementation
So, based on my answers above, here is a revised (far from perfect) implementation:
/* This is the revised engine model */
class FrameWork_Engine_Model
{
function __construct($config)
{
$this->config = $cofig;
}
public function database()
{
require_once('Database.class.php');
return new Database($this->config['configParams']);
}
public function bbcode()
{
require_once('BBCode.class.php');
return new BBCode($this->database());
}
public function image()
{
require_once('Image.class.php');
$this->image = new Image($this->config['extensionName']);
}
....
public function register_controller($shared = true)
{
if ($shared && $this->register_controller) {
return $this->register_controller;
}
return $this->register_controller = new Register_Controller($this->database(), $thus->image(), $this->bbcode());
}
}
Now, to use your services:
$container = new FrameWork_Engine_Model();
$container->register_controller()->doSomeAction()
What could be improved? Your container should:
provide a way to share services - that is, to initialise them only once
be lockable - provide a way to lock it after configuration
be able to "merge" with other containers - that way your application will be really modular
allow optional dependencies
allow scopes
support tagging services
Ready to use DI Container Implementations
All of these are accompanied with clear documentation about Dependency Injection
Pimple - PHP 5.3 lightweight DI container
Symfony2 DI Container - PHP 5.3 feature full DI container
Juice DI - Small PHP 5.2 DI container
Your FrameWork_Engine_Model is a registry (Registry Pattern). Injecting the registry as dependency into all objects is kind of a misunderstood dependency injection. Technically it is DI, but you create a dependency from everything to everything and also take away the flexibility that DI should offer.
If your FrameWork_Engine_Model was meant to instantiate services and manage their dependencies, you could change it to an Inversion of Control Container (typical pattern related to DI)
No, not in general.
I won't argue your choice of class names and the responsibilities of your services and controllers, as I don't think it is within scope of this question. Just a remark: it looks like your controllers do too much. If you are interested in clean code, you might want to have a look at the Single Responsibility Principle and keep your controllers "thin", moving business logic and database queries to a service layer and output mechanisms like bbcode to views.
So, back to your example and how to change it to a sensible usage of Dependency Injection. A primitive IoC container could look like that:
public function createRegisterController()
{
$controller = new RegisterController();
$controller->setImage($this->getImageService());
// ...
return $controller;
}
public function getImageService()
{
if ($this->imageService === null) {
$this->imageService = new Image();
// inject dependencies of Image here
}
return $this->imageService;
}
The important point here is: Only inject the dependencies that are needed. And don't create a bunch of global variables disguised as DI.