为PHP设计的一个精简、强大且完全兼容PSR-11的依赖注入库

1.1.0 2019-11-19 06:52 UTC

This package is auto-updated.

Last update: 2024-09-19 17:46:35 UTC


README

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

为PHP设计的一个精简、强大且完全兼容PSR-11的依赖注入库。

它基于功能丰富的phoole/config库,并支持对象装饰对象作用域等功能。它需要PHP 7.2+版本。它符合PSR-1PSR-4PSR-11PSR-12规范。

安装

通过 composer 工具进行安装。

composer require "phoole/di"

或者在您的 composer.json 文件中添加以下行

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

用法

  • 使用文件或定义数组中的配置

    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');

    与容器相关的配置位于 di 节点下,服务定义位于 di.service 节点下。

特性

  • 引用

    可以使用类似 '${reference}' 的形式来引用配置或容器中预定义的参数。

    引用名称中不允许使用 '$''{''}''.' 字符。字符 '#''@' 有特殊含义,因此不应包含在 普通 服务名称中。

    • 参数引用,例如 ${system.tempdir}

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

      有关详细信息,请参阅phoole/config 引用。参数引用从配置文件或数组中读取。

    • 服务引用,例如 ${#cache}

      可以使用类似 ${#serviceId} 的形式来引用容器中的服务实例。

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

      有两个保留的服务引用:${#container}${#config}。这两个引用分别指向容器实例本身及其所使用的配置实例。这两个可以像其他服务引用一样使用。

    • 使用引用

      引用可以在配置的任何位置使用。

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

    对象装饰 是在服务实例实例化前后应用装饰更改(执行方法等)。

    • 仅针对 单个实例 的装饰方法

      $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
      
                     }, 
                 ]
             ],
             ...
         ]
      ];

      通过在 cache 服务定义中添加 beforeafter 节,形式为 [callableOrMethodName, OptionalArgumentArray],这些方法将在 cache 实例化前后执行。

      callableOrMethodName 可以是:

      • 初始化对象的 method name

        ...
          'after' => [
              // $obj->setLogger($logger), $logger will be injected automatically
              'setLogger', // object implementing 'LoggerAwareInterface'
          ],
        ...
      • 一个接受初始化对象作为参数的有效可调用对象

         ...
           'after' => [
               // callable takes initiated object as parameter
               function($obj) {
               },
           ],
         ...
      • 一个具有引用的伪可调用对象(在解析引用后,它是一个有效的可调用对象)。

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

      OptionalArgumentArray 可以是:

      • 值或引用的数组

    • 针对 所有实例 的通用装饰方法

      $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
          ],
      ];

      可以在 'di.before' 或 'di.after' 节中配置通用方法,以在所有实例实例化前后应用。

  • 对象作用域

    • 共享对象和新对象

      默认情况下,容器中的服务实例在容器内是共享的。如果用户希望每次使用不同的实例,他们只需在服务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
    • 对象范围

      您可以通过以下方式在自己的 作用域 中获取一个实例:

      // 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

      服务引用也可以按如下方式定义作用域:

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

    • 静态访问预定义服务

      容器中的服务也可以通过静态方式访问。但 gethas 是保留的。

      // 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');
    • 通过依赖注入初始化对象

      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();
  • 自动装配自动注入

    • 参数自动装配(解析)

      构造器/可调用参数将通过以下方式解析:

      • 是否存在于类映射中(已创建的服务对象)?

      • 脚本中已知的类名(已定义的类)?

    • 自动注入

      我们鼓励使用 '注解' 而不是使用 *AwareInterface 来实现您自己类的依赖注入。

      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();

      Containerdi.after 部分预定义了所有常见的注入。

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

    两者都可用:ContainerAwareInterfaceContainerAwareTrait

APIs

  • 与容器相关

    • ContainerInterface 中获取 get(string $id): object

    • ContainerInterface 中获取 has(string $id): bool

      $id 可能后跟有 @@scope

测试

$ composer test

依赖关系

  • PHP >= 7.2.0

  • phoole/config >= 1.*

许可证