Requires
- php: >=7.0
README
a IOC container for php
This is a extension which implements Dependency Injection, it's itself a container and it implements the
Inversion of Control pattern.
enviroment requirement
php7.0+
Install
composer require fanqingxuan/di
If you want install it as php extension, please see di-ext. The same usage with this package.
Basic Usage
require_once 'vendor/autoload.php'; use JsonDi\Di; class Test { } $di = new Di; //注入的方式 $di->set('test', 'Test'); $di->set("test2", function () { return new Test; }); $di->set("test3", Test::class); $di->set('test4', new Test);
like you can see,there are serveral ways to register services as the follow list.
-
string
$di->set('test','Test'); $di->set("test3",Test::class);
-
object instance
$di->set('test5',new Test);
-
Closures/Anonymous functions
$di->set("test2",function() { return new Test; });
You can pass additonal parameters to closure function.
require_once 'vendor/autoload.php'; use JsonDi\Di; use JsonDi\Config; $di = new Di; $di->set('config',new Config( [ 'database' => [ 'host' => 'localhost', 'username' => 'root', 'password' => '111111' ] ] )); class MysqlDb { public function __construct($config) { print_r($config); } } $di->set('db',function () { return new MysqlDb($this->get('config')->database);//get the database config from container });
also,you can pass parameter by using the key word of use.
$config = [ 'host' => 'localhost', 'username' => 'root', 'password' => '111111' ]; $di->set('db',function () use ($config) { return new MysqlDb($config); });
Advanced Usage
-
Constructor Injection
This is injection type can pass arguments to the class constructor.
class UserService { protected $userDao; protected $userType; public function __construct(UserDao $userDao,$userType) { $this->userDao = $userDao; $this->userType = $userType; } }
We can register the service this way.
$di->set( 'userDao', [ 'className' => UserDao::class ] ); $di->set( 'userService', [ 'className' => UserService::class, 'arguments' => [ [ 'type' => 'service', 'name' => 'userDao',//another service name in the container ], [ 'type' => 'parameter', 'value' => 3 ] ] ] );
-
Setter Injection
Some class have setters for injection with their specail demand. We modify the above service as the class with setters.
class UserService { protected $userDao; protected $userType; public function setUserDao(UserDao $userDao) { $this->userDao = $userDao; } public function setUserType($userType) { $this->userType = $userType; } }
A service with setter injection can be registered as follows:
$di->set( 'userService', [ 'className' => 'UserService', 'calls' => [ [ 'method' => 'setUserDao', 'arguments' => [ [ 'type' => 'service', 'name' => 'userDao', ] ] ], [ 'method' => 'setUserType', 'arguments' => [ [ 'type' => 'parameter', 'value' => 3 ] ] ] ] ] );
You can inject parameters directly into public attributes of the class:
class UserService { public $userDao; public $userType; public $tempObj; }
A service with properties injection can be registered as follows
$di->set( 'userService', [ 'className' => UserService::class, 'properties'=>[ [ 'name' => 'userDao', 'value' => [ 'type' => 'service', 'name' => 'userDao',//service name in the container ] ], [ 'name' => 'userType', 'value' => [ 'type' => 'parameter', 'value' => 2, ] ], [ 'name' => 'tempObj', 'value' => [ 'type' => 'instance', 'className' => 'StdClass', 'arguments' => [] ] ] ] ] );
More Advanced Usage
The next we will give a way that inject service from php file.
//service.php <?php return [ 'testA' => [ 'className' => Test::class, 'shared' => true, ], ];
We can inject it to container as follows:
require_once 'vendor/autoload.php'; use Json/Config; $di = new Di; $di->loadFromPhp('service.php');
Array Syntax Usage
We introduce the usage with the set function above. In fact,the array syntax is also allowed to register as services.
$di['db'] = new StdClass; $di['db'] = function() { return new StdClass; } $di['db'] = 'StdClass'; $di['db'] = [ 'className' => 'StdClass' ]
Property Syntax Usage
We can inject the object with the property usage. Actually,it use the magic methd to realize it.
$di->db = new StdClass; $di->db = function() { return new StdClass; } $di->db = StdClass::class; $di->db = [ 'className' => 'stdClass' ];
Get Services
-
get method
$di->get('db');
-
magic method
$di->getDb();
-
array-access syntax
$di['db'];
-
property syntax
$di->db;
Shared Services
Services can be registered as ‘shared’ services this means that they always will act as singletons. Once the service is resolved for the first time the same instance of it is returned every time.
$di->setShared( 'db', function() { return new MysqlDb(); } );
or use the set method with its third parameter as 'true'.
$di->set( 'db', function() { return new MysqlDb(); }, true );
Modify the Services
When the service is registered in the container,you can get it and modify it.
class Test { } //register service $di->set('test','StdClass'); //get service $test = $di->getService('test'); //change the definition $test->setDefinition(function() { return new Test; }); //resolve the service $test->resolve();
Automatic Inject the DI Container into the service
DI Container is used for inject other service into it. but sometimes the service itself need the the other instance from the container. If a class or component requires the DI itself to locate services, the DI can automatically inject itself to the instances it creates, to do this, you need to extends the JsonDi\Di\AbstractInjectionAware class in your classes:
require_once 'vendor/autoload.php'; use JsonDi\Di; use JsonDi\Di\AbstractInjectionAware; class Mysql { public function select() { return "this is select"; } } class HomeController extends AbstractInjectionAware { public function say() { echo $this->container->get('db')->select(); } } $di = new Di; $di->set('db', Mysql::class); $di->set('home', HomeController::class); $di->get('home')->say();
Service Providers
Using the JsonDi\Di\ServiceProviderInterface you now register services by context. You can move all your $di->set()
calls to classes as follows. Notice return void for the register function.
require_once 'vendor/autoload.php'; use JsonDi\Di\DiInterface; use JsonDi\Di\ServiceProviderInterface; class SessionServiceProvider implements ServiceProviderInterface { public function register(DiInterface $di):void { $di->set( 'session', 'SessionClass' ); } } $di->register(new SessionServiceProvider()); $di->get('session');