php DI container - php

i don´t have a lot of php experience i'd need some help,
i have a php MVC framework,
i use this class:
class Registry {
private $objects;
private $settings;
public function __construct() {
}
public function iniObject($class, $key)
{
$this->objects[ $key ] = new $class( $this );
}
public function getObject( $key )
{
return $this->objects[ $key ];
}
public function storeSetting( $setting, $key )
{
$this->settings[ $key ] = $setting;
}
public function getSetting( $key )
{
return $this->settings[ $key ];
}
}
then i pass the registry to the other classes like:
Class Controller
{
/*
* #registry object
*/
protected $registry;
function __construct(Registry $registry)
{
$this->registry = $registry;
//i can use any class from my registry class like the logger class below
$this->registry->getObject('log')->write_log('debug', "Controller Class Initialized");
}
/**
* #all controllers must contain an index method
*/
public function index() {}
}
i start my bootstrap.php with
$registry = new Registry();
// Instantiate some classes
$registry->iniObject( 'Utf8', 'utf8');
$registry->iniObject( 'Uri', 'uri');
$registry->iniObject( 'Router', 'router');
i get any method like:
$registry->getObject('router')->_set_routing();
and i get a view like:
$registry->getObject('output')->_display('myview');
in this way i can use all the classes inside other classes
passing the registry class like DI constructor, works well,
few code and fast execution,
i've been reading about DI containers and other things,
i'd like to know a better ways to do this, if the registry gets
bigger and bigger how will affect the framework i mean i pass
all the registry to every class, there´s a way to pass just
dependencies that every class needs instead the full registry,
is the registry the best way to work with objects cos allow me
to use any class inside any other class or you thing this isn´t a good
way to do it, any recommendation about DI containers libraries,
please i'd like to recieve ideas from more experienced php
programmers to do this
thanks a lot

While I am not an expert, I am currently using the yadif DI framework in my project (https://github.com/beberlei/yadif). I have modified it slightly to suit my purposes.
While the dependency injection and the registry object allows you to access an object from anywhere, I believe the difference is that in dependency injection, the dependecy object is instantiated and passed into the requiring object when it is instantiated.
This passing in can be done via the constructor or by setting properties of the requiring object.
The main point is then that the requiring object and its dependencies are loosely coupled.
As a quick example, imagine that I have a User class that depends on the Database class. The database class would return some information to the User class. However, if I am doing unit testing, I would like to test the User class on its on, with my own set of inputs. With dependency injection, I can easily inject my own mock objects (inputs) into the user class without having to set up a database with the test data and depend on the database to access and return that data to us.
Having said that, dependency injection is not a must or required for all projects. For example, a complex dependency injection framework may affect the performance or introduce unneeded complexity into your application.

You are injecting the whole registry. I suggest you should simply inject your dependency directly:
class Foo {
/**
* #Inject
* #var MyLogClass
*/
private $log;
}
That way your code is simpler to read and write, and you don't have to care about your registry.
This is possible for example with PHP-DI which works with annotations like the DI container you are using.

Related

Better way to create objects with dependencies in PHP

I am currently working on a PHP project where I need to create objects of a class RelevantClass. I am using Dependency Injection via DI Container.
Underlying Structure
Let's suppose I have the following class structure:
class SomeServiceClass {
}
class EntityClass {
}
class RelevantClass {
/**
* #Inject
*/
private SomeServiceClass $service
public function __construct(EntityClass $entity){
$this->service = inject(SomeServiceClass::class)
$this->entity = $entity;
}
public function someMethod() : void
{
...
$this->service->doSomething($this->entity);
$this->entity->doSomething();
...
}
}
The issue here is that my EntityClassObject needs to be modified by my RelevantClass, as in I can't pass in an injected instance of EntityClass into the constructor of RelevantClass.
The Service class includes some helper methods and other functionality, so it can be injected directly.
Now my question is, how should I instantiate my RelevantClass class?
Approach 1
The way it works right now is that I simply call the constructor:
$entity = ... # Getting the entity from the database
$relevantObject = RelevantClass($entity); # here my service is instantiated by explicitly calling the di container
$relevantObject->someMethod();
That way, my Service is set by the constructor via injection container and my entity is passed through the constructor argument.
Approach 2
Although it is working, I am wondering if it were better practice if I structured my RelevantClass in a way that allows me to instantiate it via DI Container, too?
$entity = ... # Getting the entity from the database
$relevantObject = inject(RelevantClass::class); # this would inject my service class as well
$relevantObject->setEntity($entity);
$relevantObject->someMethod();
Briefly summed up, someMethod needs SomeServiceClass to perform some operations on an EntityClass instance. SomeServiceClass can be injected, while EntityClass cannot.
What is the way to go here? I am aware that both approaches woudl work, but which one of them would be best practice? The project I am currently working on barely uses the constructor to instantiate classes, so I am wondering, whether there are any inherent advantages to the second approach?

PHP OOP: How to bundle multple classes together

I have been reading up on OOP for a while now and it's always confused me but I'm trying to improve on my skills (albeit I'm still starting out with this so please be kind).
I am designing a main app, whose "core" class is $App. My thought is that anywhere in the app, you can do everything from within $App.
For example, I have a $Db class to query the database, $Mail class for sending email, etc. These are all autoloaded using spl_autoload_register.
My question is in regards to actually instantiating them properly. Here's how I'm doing it now:
index.php
require_once('config.php'); // Autoloads classes and some other small stuff
$App = new App;
echo $App->Visitor->getIP();
App.class.php
class App {
public function __construct() {
$this->initialize();
}
private function initialize() {
$this->Visitor = new Visitor($this);
$this->Db = new Db($this);
$this->Mail = new Mail($this);
}
// Then some public methods...
// We are able to use $this->Visitor, $this->Db, etc...
}
Visitor.class.php
class Visitor {
private $App;
public function __construct($App) {
$this->App = $App; // I need access to all of App's methods
}
public function getIP() {
return $_SERVER['REMOTE_ADDR'];
}
}
So the short example above shows how I'm doing this in all my classes. The App class always creates an instance of whatever class we will be using in the entire app in it's constructor.
The "child" classes all [dependency injects?] the $App instance so they can use it's methods.
Am I doing this correctly? It works, but I don't know if there is a more efficient/better practice way of doing this.
The problem with injecting the base class on instantiation is that it makes all of your classes have really ambiguous dependencies. Your Visitor class could rely on a class that parses the $_SERVER superglobal, but I can't tell just by looking at it, it's only dependency is the whole app object.
It's much better to only define the specific dependencies a class needs (usually in the constructor) and create something whose job it is to properly provide these dependencies. This is the "dependency injection" that you were hinting at, and they usually involve some Container that stores all the objects that have been instantiated, ready to inject into new classes.
So your app will have the dependency of a container:
$app = new App(new Container);
And then you can ask the container for dependencies
class App {
/**
* #return App\Visitor
*/
public function getVisitor()
{
if (!$this->visitor) {
$this->visitor = $this->container->get('App\Visitor');
}
return $this->visitor;
}
}
If you use a third party dependency injection library (recommended - even when starting out as designing your own is a bit of a tangent) then the library will usually provide some way to automatically resolve dependencies. It can look at the constructor on your class (that's typehinted correctly, e.g. __construct(Visitor $visitor)) and automatically provide the arguments to the constructor - using the Reflection SPL
I would also recommend if you're starting out with OOP that you first familiarise yourself with PSR-4 and Composer autoloading, as including all of your classes manually is going to become quite a hassle, and doing it the "standard" way at the beginning makes life easier in the future when you will want to switch ;) .

What is a Dependency Injection Container?

I am trying to understand the role of a Dependency Injection Container because it strikes me as fundamental in maintainable code.
As I understand it, a DIC is just as the title suggests: a container where all your dependencies are collected together. Instead of seeing new Foo\Bar all over the application, all the new instances are generated inside of the container and then passed through to each other where they are needed (e.g., Model is instantiated with an instance of Database, which is instantiated with an Instance of Config).
I have attempted to make a very simple DIC. This is the result.
In my front controller I am instantiating a new App\Core\Container.
My Container looks like this:
<?php
namespace App\Core;
use App\Config;
class Container
{
public $config;
public $router;
public $database;
public $model;
public $view;
public $controller;
public function __construct()
{
$this->config = new Config;
$this->router = new Router;
$this->database = new Database($this->config);
}
public function add()
{
// add dependencies from the outside?
}
public function getInstance(/* string */)
{
// return an instance for use somewhere?
}
public function newModel($model)
{
$model = $this->getModelNamespace() . $model;
$this->model = new $model($this->database);
return $this->model;
}
private function getModelNamespace()
{
$namespace = 'App\Models\\';
if (array_key_exists('namespace', $this->params = [])) {
$namespace .= $this->params['namespace'] . '\\';
}
return $namespace;
}
public function newView($params)
{
$this->view = new View($this->model, $params);
return $this->view;
}
public function newController($controller)
{
$controller = $this->getControllerNamespace() . $controller;
$this->controller = new $controller;
return $this->controller;
}
private function getControllerNamespace()
{
$namespace = 'App\Controllers\\';
if (array_key_exists('namespace', $this->params = [])) {
$namespace .= $this->params['namespace'] . '\\';
}
return $namespace;
}
}
Questions
Could my implementation above, although very simple, be classed as a basic dependency injector?
Is a Dependency Injection Container generally comprised of one class?
Note: the first three headings answer your questions, while the following ones answer anticipated questions and provide coverage of anything in the first two sections.
Could this be classified as a dependency injection container?
No, this does not look like a dependency injection container. A dependency injection container is meant to reduce the work that instantiation requires by determining, creating, and injecting all dependencies. Rather what you have there appears to be a combination of a factory and a service locator.
Factories abstract the creation of objects. This is essentially what your Container class is doing. By calling designated methods (i.e., newModel), your container takes on the responsibility of locating the exact object to be instantiated and constructing an instance of that object.
The reason I would call this a "poor" factory is that it's beginning to look like it might be used to locate services. Service locators work by hiding an object's dependencies: instead of being dependent on GenericService, an object might depend on a service locator. Given the service locator, it can request an instance of GenericService. I see similar behavior beginning to take hold in your add() and getInstance() methods. Service locators are generally considered anti-patterns because they abstract dependencies therefore making code impossible to test!
Is a dependency injection container comprised of one class?
It depends. You could very easily make a simple dependency injection container with one class. The issue is that the nature of a simple container tends to get more advanced into a not-so-simple container. When you start improving your pattern, you need to consider how the different components play together. Ask yourself: do they follow SOLID principles? If not, refactoring is necessary.
What is a dependency injection container?
I said it above, but again: a dependency injection container is meant to reduce the work that instantiation requires by determining, creating, and injecting all dependencies. A DIC will look at all dependencies of a class, and all dependencies those dependencies may have, and so on... In this sense, the container is responsible for hierarchically instantiating all dependencies.
The Container class you provide relies on very strict definitions of pre-defined classes. For example, classes in your model layer appear to only be dependent on a database connection. (Similar statements can be said about classes in your controller & view layer).
How does a dependency injection container find dependencies?
A dependency injection container will detect dependencies. Typically this happens through 1 of 3 mechanisms: autowiring, annotations, and definitions. PHP-DI docs provide a good idea of what all three of these entail here. In short, though: autowiring detects dependencies by reflecting on a class, annotations are used to write in dependencies using comments above a class, and definitions are used to hard-code dependencies. Personally, I prefer autowiring because it's clean & simple.
Can I create a simple dependency injection container or no?
Yes, you can. Start with the idea that an injector should be able to instantiate any object (service, view, controller, etc...). It needs to look at the relevant object and hierarchically instantiate all dependencies (hint: possibly through some method of recursion).
A quick example of a simple injector using autowiring looks like this:
<?php
class Injector
{
public function make($className)
{
$dependencies = [];
//Create reflection of the class-to-make's constructor to get dependencies
$classReflection = new ReflectionMethod($className, "__construct");
foreach($classReflection->getParameters() as $parameter) {
$dependencyName = $parameter->getClass()->getName();
//Use the injector to make an instance of the dependency
$dependencies[] = $this->make($dependencyName);
}
$class = new ReflectionClass($className);
//Instantiate the class with all dependencies
return $class->newInstanceArgs($dependencies);
}
}
Tested with something like the following, you can see how the injector recursively checks and instantiates all dependencies
class A {
protected $b;
public function __construct(B $b) { $this->b = $b; }
public function output(){ $this->b->foo(); }
}
class B {
protected $c;
public function __construct(C $c) { $this->c = $c; }
public function foo() { $this->c->bar(); }
}
class C {
public function __construct() { }
public function bar() { echo "World!"; }
}
$injector = new Injector;
$a = $injector->make("A");
//No need to manually instantiate A's dependency, B, or B's dependency, C
$a->output();
This basic injector has obvious faults. For example, there is an opportunity to create a recursion disaster if two classes are dependent on each other (there should be a check for that). However, as is, this works as a basic example of what an injector looks like.
Injector vs. Dependency Injection Container
To make this more powerful and fall under the definition of "dependency injection container", you'd want a way to share instantiated instances across multiple make() calls. For example, you may have another method called share(). This method would store the instance passed to it. Whenever a class is built through the make() method and depends on a class previously shared, instead of instantiating a new instance, it would use the already-instantiated one.
For a simple & powerful dependency injection container I suggest Auryn, but by all means, try to understand & create your own before using the ones already available.

PHP Dependency Injection

I'm trying to get my head around Dependency Injection and I understand it, for the most part.
However, say if, for some reason, one of my classes was dependent on several classes, instead of passing all of these to this one class in the constructor, is there a better, more sensible method?
I've heard about DI Containers, is this how I would go about solving this problem? Where should I start with this solution? Do I pass the dependencies to my DIC, and then pass this to the class that needs these dependencies?
Any help that would point me in the right direction would be fantastic.
Dependency Injection !== DIC
People should really stop confusing them. Dependency Injection is idea that comes from Dependency Inversion principle.
The DIC is "magic cure", which promises to let you use dependency injection, but in PHP is usually implemented by breaking every other principle of object oriented programming. The worst implementations tend to also attach it all to global state, via static Registry or Singleton.
Anyway, if your class depends on too many other classes, then in general , it signifies a design flaw in the class itself. You basically have a class with too many reasons to change, thus, breaking the Single Responsibility principle.
In this case, then dependency injection container will only hide the underlaying design issues.
If you want to learn more about Dependency Injection, i would recommend for you to watch the "Clean Code Talks" on youtube:
The Clean Code Talks - Don't Look For Things!
The Clean Code Talks - "Global State and Singletons"
If you have several dependencies to deal with, then yes a DI container can be the solution.
The DI container can be an object or array constructed of the various dependent object you need, which gets passed to the constructor and unpacked.
Suppose you needed a config object, a database connection, and a client info object passed to each of your classes. You can create an array which holds them:
// Assume each is created or accessed as a singleton, however needed...
// This may be created globally at the top of your script, and passed into each newly
// instantiated class
$di_container = array(
'config' = new Config(),
'db' = new DB($user, $pass, $db, $whatever),
'client' = new ClientInfo($clientid)
);
And your class constructors accept the DI container as a parameter:
class SomeClass {
private $config;
private $db;
private $client;
public function __construct(&$di_container) {
$this->config = $di_container['config'];
$this->db = $di_container['db'];
$this->client = $di_container['client'];
}
}
Instead of an array as I did above (which is simple), you might also create the DI container as an class itself and instantiate it with the component classes injected into it individually. One benefit to using an object instead of an array is that by default it will be passed by reference into the classes using it, while an array is passed by value (though objects inside the array are still references).
Edit
There are some ways in which an object is more flexible than an array, although more complicated to code initially.
The container object may also create/instantiate the contained classes in its constructor as well (rather than creating them outside and passing them in). This can save you some coding on each script that uses it, as you only need to instantiate one object (which itself instantiates several others).
Class DIContainer {
public $config;
public $db;
public $client;
// The DI container can build its own member objects
public function __construct($params....) {
$this->config = new Config();
// These vars might be passed in the constructor, or could be constants, or something else
$this->db = new DB($user, $pass, $db, $whatever);
// Same here - the var may come from the constructor, $_SESSION, or somewhere else
$this->client = new ClientInfo($clientid);
}
}
I've wrote an article about this problem.
The ideea is to use a combination of abstract factory and dependency injection to achieve transparent dependency resolving of (possible nested) dependencies. I will copy/paste here the main code snippets:
namespace Gica\Interfaces\Dependency;
interface AbstractFactory
{
public function createObject($objectClass, $constructorArguments = []);
}
The abstract factory implementation is:
namespace Gica\Dependency;
class AbstractFactory implements \Gica\Interfaces\Dependency\AbstractFactory, \Gica\Interfaces\Dependency\WithDependencyInjector
{
use WithDependencyInjector;
/**
* #param string $objectClass
* #param array $constructorArguments
* #return object instanceof $class
*/
public function createObject($objectClass, $constructorArguments = [])
{
$instance = new $objectClass(...$constructorArguments);
$this->getDependencyInjector()->resolveDependencies($instance);
return $instance;
}
}
The dependency injector is this:
namespace Gica\Dependency;
class DependencyInjector implements \Gica\Interfaces\Dependency\DependencyInjector
{
use \Gica\Traits\WithDependencyContainer;
public function resolveDependencies($instance)
{
$sm = $this->getDependencyInjectionContainer();
if ($instance instanceof \Gica\Interfaces\WithAuthenticator) {
$instance->setAuthenticator($sm->get(\Gica\Interfaces\Authentication\Authenticator::class));
}
if ($instance instanceof \Gica\Interfaces\WithPdo) {
$instance->setPdo($sm->get(\Gica\SqlQuery\Connection::class));
}
if ($instance instanceof \Gica\Interfaces\Dependency\WithAbstractFactory) {
$instance->setAbstractFactory($sm->get(\Gica\Interfaces\Dependency\AbstractFactory::class));
}
//... all the dependency declaring interfaces go below
}
}
The dependency container is the standard one.
The client code could look something like this:
$abstractFactory = $container->get(\Gica\Interfaces\Dependency\AbstractFactory::class);
$someHelper = $abstractFactory->createObject(\Web\Helper\SomeHelper::class);
echo $someHelper->helpAction();
Notice that dependencies are hidden, and we can focus on the main bussiness. My client code doesn't care or know that $someHelper need an Authenticator or that helpAction need an SomeObject to do its work;
In the background a lot of things happen, a lot of dependencies are detected, resolved and injected.
Notice that I don't use the new operator to create $someObject. The responsability of actual creation of the object is passed to the AbstractFactory
P.S. Gica is my nickname :)
I recommend you to use Singltones or Mutlitones. In these cases you will be always able to get objects via static class' methods.
The other way (couldn't find a correct pattern name, but it could be Registry) is to use one global static object to store multiple objects' instances. E.g. (simplified code, without any checks):
class Registry {
private static $instances = array();
public static function add($k, $v) {
$this->instances[$k] = $v;
}
public static function get($k) {
return $this->instances[$k];
}
}
class MyClass {
public function __construct() {
Registry::add('myclass', $this);
}
}

Is this a sane implementation of constructor injection?

Following on from my question on service locators I have decided to use constructor injection instead. Please consider the following code:
<?php
interface IAppServiceRegistry {
public function getDb();
public function getLogger();
}
interface IFooServiceRegistry extends IAppServiceRegistry {
public function getFooBarBazModel();
}
class AppServiceRegistry
implements IAppServiceRegistry, IFooServiceRegistry
{
private $logger;
private $db;
private $fooBarBazModel;
public function getDb() {
// return db (instantiate if first call)
}
public function getLogger() {
// return logger (instantiate if first call)
}
public function getFooBarBazModel() {
if (!isset($this->fooBarBazModel)) {
$this->fooBarBazModel = new FooBarBazModel( $this->getDb() );
}
return $this->fooBarBazModel;
}
}
// Example client classes:
/**
* Depends on db, logger and foomodel.
*/
class Foo {
private $db;
private $logger;
private $fooModel;
public function __construct(IFooServiceRegistry $services) {
$this->db = $services->getDb();
$this->logger = $services->getLogger();
$this->fooModel = $services->getFooModel();
}
}
/**
* Depends on only db and logger.
*/
class BarBaz {
private $db;
private $logger;
public function __construct(IAppServiceRegistry $services) {
$this->db = $services->getDb();
$this->logger = $services->getLogger();
}
}
Then I would add new service factory methods to the registry as the application evolved, creating segregated interfaces wherever logically appropriate.
Is this approach sane?
Although I don't normally read php, I think I understand most of it. Technically, it looks fine, but then you write
I would add new service factory methods to the registry as the application evolved
That tends to hurt the idea of loose coupling because instead of a general-purpose Service Locator you now have a specialized Service Locator.
Injecting such a serivce registry into each class works against the Single Responsibility Principle (SRP) because once a class has access to the registry, it is too easy to request yet another dependency than originally conceived, and you will end up with a God Object.
It would be better to inject the required dependencies directly into the classes that need them. Thus, your Foo class' constructor should take a db, a logger and a fooModel, while the BarBaz class should take only a db and a logger parameter.
The next question may then be: What if I need a lot of different dependencies to perform the work? That would require a truly ugly constructor with lots of parameters, and this goes against other well-known OO practices.
True, but if you need lots of dependencies, you are probably violating the SRP and should try to split your design into finer-grained objects :)
This implementation is almost the same as the service locator you previously showed us.
A good question to ask is whether upon looking at the class of your objects, you know everything about the objects needs to get their job done. In your case you still don't know.
If Foo needs the db, logger and model, you make this clear by asking for these in the constructor.
Here's a good read on the matter:
http://misko.hevery.com/code-reviewers-guide/flaw-digging-into-collaborators/
I've been grappling with this kind of problem lately. Service Locator vs Depedency Injection.
I agree with Mark that the way to go is to inject individual fine-grained objects into the constructor, as required. The only drawback, as Mark has highlighted, is that when you build a complex object graph, you inevitably have to start somewhere. This means that your high-level objects will have lots of services (objects) injected into them.
The easy way round this is to use something to do the hard work for you. The prime example of this is Google's Guice which seems to me a very good way of going about things. Sadly it's written for Java! There are PHP versions about; I'm not sure any of them quite measure up to Guice at this point.
I've written a post on this topic which goes into more detail; which you may find interesting. It includes a simple implementation of a dependency injection framework.
The bottom line is that if you've got a class Foo with a number of requirements, you can create your class as such:
/**
* Depends on db, logger and foomodel.
*/
class Foo
{
private $db;
private $logger;
private $fooModel;
/**
* (other documentation here)
* #inject
*/
public function __construct(IDbService $db, ILoggerService $logger, $iModelService $model)
{
// do something
}
}
When you want a new Foo object, you simply ask the dependency injection framework to create you one:
$foo = $serviceInjector->getInstance('Foo');
The dependency injector will do the hard work, making sure it injects the dependencies. This includes any dependencies of the dependencies, if that makes sense. In other words it will sort it all out recursively up the tree.
Later, when you find you need an IBarService object, you can just add it to the Construtor, without altering any other code!

Categories