Skip to content

phoole/di

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

19 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

di

Build Status Scrutinizer Code Quality Code Climate PHP 7 Latest Stable Version License

Slim, powerful and full compatible PSR-11 dependency injection library for PHP.

It builds upon the versatile phoole/config library and supports object decorating, object scope and more. It requires PHP 7.2+. It is compliant with PSR-1, PSR-4, PSR-11 and PSR-12.

Installation

Install via the composer utility.

composer require "phoole/di" 

or add the following lines to your composer.json

{ "require": { "phoole/di": "1.*" } }

Usage

  • With configuration from files or definition array

    use Phoole\Di\Container; use Phoole\Config\Config; use Phoole\Cache\Cache; use Phoole\Cache\Adaptor\FileAdaptor; $configData = [ // service definitions 'di.service' => [ // classname & constructor arguments 'cache' => [ 'class' => Cache::class, 'args' => ['${#cacheDriver}'] // optional ], // use classname directly 'cacheDriver' => FileAdaptor::class ], // methods to run after each object initiation 'di.after' => [ // a callable, takes THE object as parameter function($obj) { echo "ok"; }, // will be converted to $obj->setLogger($logger) 'setLogger', ] ]; // inject configurations into container $container = new Container(new Config($configData)); // get service by id 'cache' (di.service.cache) $cache = $container->get('cache');

    Container related configurations are under the node di and service definitions are under the di.service node.

Features

  • References

    References in the form of '${reference}' can be used to refer to predefined parameters from the config or services in the container.

    Characters of '$', '{', '}', '.' are not allowed in reference name. Characters of '#', '@' have special meanings, such that should not be part of normal service names.

    • Parameter references like ${system.tempdir}

      $config = [ ... // use predefined 'sytem.tmpdir' in arguments etc. 'di.service.cacheDriver' => [ 'class' => FileAdaptor::class, 'args' => ['${system.tmpdir}'], ], ... ];

      See phoole/config reference for detail. Parameter references are read from configuration files or array.

    • Service references like ${#cache}

      Service object reference in the form of ${#serviceId} can be used to referring a service instance in the container.

      $configData = [ ... 'di.service' => [ 'cache' => [ 'class' => Cache::class, 'args' => ['${#cacheDriver}'] // object reference ], 'cacheDriver' => ... ...

      Two reserved service references are ${#container} and ${#config}. These two are referring the container instance itself and the config instance it is using. These two can be used just like other service references.

    • Using references

      References can be used anywhere in the configuration.

      $confData = [ // methods executed after ALL object initiation 'di.after' => [ [['${#logger}', 'notice'], ['object created using ${log.facility}']] ] ];
  • Object decorating

    Object decorating is to apply decorating changes (executing methods etc.) right before or after the instantiation of a service instance.

    • Decorating methods for individual instance only

      $config = [ 'di.service' => [ ... 'cache', [ 'class' => '${cache.class}', 'args' => ['${#cachedriver}'], // constructor arguments 'before' => [ [['${#logger}', 'info'], ['before initiating cache']], // $logger->info(...) ], 'after' => [ 'clearCache', // $cache->clearCache() method ['setLogger', ['${#logger}']], // $cache->setLogger($logger), argument is optional [['${#logger}', 'info'], ['just a info']], // $logger->info(...) function($cache) { // a callable takes object in parameter }, ] ], ... ] ];

      By adding before or after section into the cache service definition in the form of [callableOrMethodName, OptionalArgumentArray], these methods will be executed right before/after cache instantiation.

      callableOrMethodName here can be,

      • method name of initiated object

        ... 'after' => [ // $obj->setLogger($logger), $logger will be injected automatically 'setLogger', // object implementing 'LoggerAwareInterface' ], ...
      • a valid callable which takes initiated object as parameter

         ... 'after' => [ // callable takes initiated object as parameter function($obj) { }, ], ...
      • a pseudo callable with references (after resolving the references, it is a valid callable).

         ... 'after' => [ // a pseudo callable with references [['${#logger}', 'info'], ['just a info']], // $logger->info(...) ], ...

      OptionalArgumentArray here can be,

      • empty

      • array of values or references

    • Common decorating methods for all instances

      $configData = [ // before all instances initiated 'di.before' => [ [['${#logger}', 'info'], ['before create']], ], // after methods for all instances 'di.after' => [ ['setLogger', ['${#logger}']], // arguments are optional 'setDispatcher', // simple enough, set event dispatcher ], ];

      Common methods can be configured in the 'di.before' or 'di.after' node to apply to all the instances right before or after their instantiation.

  • Object scope

    • Shared objects and new objects

      By default, service instances in the container are shared inside the container. If users want different instance each time, they may just append '@' to the service id.

      // cache service by default is in shared scope $cache1 = $container->get('cache'); // get again $cache2 = $container->get('cache'); // same var_dump($cache1 === $cache2); // true // get a NEW cache instance $cache3 = $container->get('cache@'); // different instances var_dump($cache1 !== $cache3); // true // but both share the same cacheDriver dependent service var_dump($cache1->getAdaptor() === $cache3->getAdaptor()); // true
    • Object scope

      You may get an instance in your own scope as follows

      // no scope $cache1 = $container->get('cache'); // in `myScope` $cache2 = $container->get('cache@myScope'); // different instances var_dump($cache1 !== $cache2); // true // shared in myScope $cache3 = $container->get('cache@myScope'); var_dump($cache2 === $cache2); // true

      Service references can also have scope defined as follows,

      $container->set('cache', [ 'class' => Cache::class, 'args' => ['${#driver@myScope}'] // use driver of myScope ]);
  • Static access

    • Access predefined services statically

      Services in the container can also be access through a static way. But get and has are reserved.

      // after container initiated $container = new Container(new Config(...)); // equals to $cache = $container->get('cache') $cache = Container::cache(); // if myservice defined and invokable $obj = Container::myservice('test');
    • Initiating object by taking advantage of dependency injection

      use Phoole\Cache\Cache; use Psr\Log\LoggerAwareTrait; use Psr\Log\LoggerAwareInterface; class MyClass implements LoggerAwareInterface { use LoggerAwareTrait; public function __construct(Cache $cache) { } } // $cache will be injected automatically $obj = Container::create(MyClass::class); // also 'setLogger' will be executed if defined in 'di.after' section $logger = $obj->getLogger();
  • Autowiring and auto injection

    • Parameter autowiring (resolving)

      Parameters of a constructor/callable will be resolved by looking

      • exists in the classmap (service objects created already) ?

      • classname known to the script (class defined already) ?

    • Auto injection

      Instead of using 'annotation', we encourage of using *AwareInterface for your own classes' dependency injection.

      use Psr\Log\LoggerAwareTrait; use Psr\Log\LoggerAwareInterface; class MyOwnClass implements LoggerAwareInterface { use LoggerAwareTrait; ... } // create your object with arguments $obj = Container::create(MyOnwClass::class, [...]); // $logger injected by the container automatically $logger = $obj->getLogger();

      Container has all the common injection predefined in the di.after section

      $config = [ 'di.after' => [ 'setLogger', // logger aware 'setCache', // cache aware 'setDispatcher', // event aware 'setContainer', // container aware ... ], ]; ...
  • ContainerAWareInterface

    Both ContainerAWareInterface and ContainerAWareTrait available.

APIs

  • Container related

    • get(string $id): object from ContainerInterface

    • has(string $id): bool from ContainerInterface

      $id may have @ or @scope appended.

Testing

$ composer test

Dependencies

  • PHP >= 7.2.0

  • phoole/config >= 1.*

License

About

Slim, powerful and full compatible PSR-11 dependency injection library for PHP

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •  

Languages