该软件包已被废弃,不再维护。作者建议使用knot-lib/di软件包。

类似于Pimple的依赖注入(DI)容器库。

0.2.0 2019-12-03 22:40 UTC

This package is auto-updated.

Last update: 2019-12-09 09:17:11 UTC


README

Latest Version on Packagist Software License Build Status Coverage Status Code Climate Total Downloads

描述

Calgamo/Di 是一个类似Pimple风格的依赖注入(DI)容器库。

Pimple

特性

  • Pimple风格API
  • 懒加载以提高性能
  • 多容器构建器
  • 保护或限制组件
  • 可缓存
  • 动态代码生成以启动
  • 依赖注入
    • 自动装配
    • 构造函数、setter、字段注入
    • 作用域:单例/原型
    • 自定义注解
      • @Inject
      • @Scope
      • @Singleton
      • @Named
      • @Prototype

要求

PHP 7.1 或更高版本

安装 calgamo/di

推荐通过Composer 安装 calgamo/di。

composer require calgamo/di

安装后,您需要要求 Composer 的自动加载器

require 'vendor/autoload.php';

用法

1. 构建容器

容器可以通过构建器类或直接创建。您可以根据喜好选择容器创建方式。
有几种容器构建方法

  • 简单(无容器构建器)
  • 启动容器构建器
  • 编译容器构建器
  • 模块化容器构建器
  • 缓存编译容器构建器

简单(无容器构建器)

您可以在没有任何内置容器构建器的情况下构建容器。
这种方法简单且最快,但如果使用很多组件,容器初始化代码会变得复杂。

use Calgamo\Di\Container;
use Sample\Person;
 
$container = Container();
$container['david'] = function(Container $c){
   return new Person('David Smith', 24, 179.2, function($target){ return 'throws '.$target.'.'; });
};
 
$david = $container['david'];
$david->sayHello();        // David Smith says "Hello! My name is David Smith. I am 24 years old."

启动容器构建器

启动容器构建器将通过回调函数(启动)中编写的代码设置容器。这种方法非常快,但可能有些冗余。

use Calgamo\Di\Container;
use Calgamo\Di\BootstrapContainerBuilder;
use Sample\Person;
  
$bootstrap = function(Container $c){
       $c['david'] = function(Container $c){
           return new Person('David Smith', 24, 179.2, function($target){ return 'throws '.$target.'.'; });
       };
   };
$bulder = new BootstrapContainerBuilder($bootstrap);
$container = $bulder->build();
  
$david = $container['david'];
$david->sayHello();        // David Smith says "Hello! My name is David Smith. I am 24 years old."

编译容器构建器

编译容器构建器将通过配置文件(支持 .json/.yml/.php)设置容器。此容器构建器在缓存目录中动态生成启动代码,因此第二次激活容器的启动时间将大大减少。

sample.php
use Calgamo\Di\CompilerContainerBuilder;
use Calgamo\Config\Util\ConfigFileUtil;
  
$config = ConfigFileUtil::loadConfigFromFile('components.json');
$container = (new CompilerContainerBuilder($config))->build();
  
$david = $container['david'];
$david->sayHello();        // David Smith says "Hello! My name is David Smith. I am 24 years old."
components.json
{
  "compiler": {
    "vendor_dir": "../vendor",
    "autoloaders": [
      "../sample_autoloader2.php"
    ]
  },
  
  "cache": {
    "root": "../cache",
    "filename": "demo_di"
  },
 
  "components": [
    {
      "id": "david",
      "type": "object",
      "class_name": "Sample\\Person",
      "injections": [
        {
          "new": [ "David Smith", "@int: 24", "@float: 179.2", "@func: function($target){ return 'throws '.$target.'.'; }" ]
        }
      ]
    }
  ]
}
@ 指令

如上述配置文件(components.json),您可以在组件配置文件中使用 '@xxx' 指令。
以下有一些 '@xxx' 指令。

指令 替换 示例
@id: [component_id] 通过 [component_id] 识别的其他组件 @id: logger
@func: [function_code] [function_code] @func: function($a) { echo $s; }
@int: [integer_value] [integer_value] @int: 100
@float: [float_value] [float_value] @float: 3.14
@bool: [bool_value] 将布尔值['yes'、'1'、'on']视为真 @bool: yes
@bool: true
@json: [json_data] 解码后的json @json: { 'age': '21', 'name': 'david' }
@env: [key] $_ENV值($_ENV['key']) @env: USER

模块化容器构建器

模块化容器构建器通过安装"容器模块"来设置容器。容器模块是一组容器初始化代码。
BootstrapContainerBuilder只提供一组初始化代码,但ModularContainerBuilder如果需要可以接受多个模块。

use Calgamo\Di\Container;
use Calgamo\Di\ModularContainerBuilder;
use Calgamo\Di\ContainerModuleInterface;
use Sample\Person;
 
class DavidModule implements ContainerModuleInterface
{
    public function install(Container $container)
    {
        $container['david'] = function(){
           return new Person('David Smith', 24, 179.2, function($target){ return 'throws '.$target.'.'; });
        };
    }
}
 
$builder = new ModularContainerBuilder([ new DavidModule() ]);
$container = $builder->build();
 
$david = $container['david'];
$david->sayHello();        // David Smith says "Hello! My name is David Smith. I am 24 years old."

2.使用容器

get

// get service
$service = $container['my-service'];
 
// do something
$service->doSomething();

set/unset

您可以使用相同的方式将实例或值设置为容器中。您还可以设置用于生成实例的工厂代码或用于延迟创建的常量值。

// set object
$container['my-favorite-fruits'] = new MyService();
 
// set object factory(lazy creation)
$container['my-service'] = function(){
    return new MyService();
};
  
// set constant value
$container['my-favorite-fruits'] = [ 'apple', 'banana' ];
  
// set constant value factory(lazy creation)
$container['my-service'] = function(){
    return [ 'apple', 'banana' ];
};
 
// unset entry
unset($container['my-favorite-fruits']);

slot

槽位是关于容器组件的信息。您可以通过槽位对象锁定或限制组件。

// get slot object
$slot = $contianer->slot('something');
 
// lock the slot(in this case, 'something' slot will be locked)
$slot->lock();
 
// type restriction
$slot->mustBeTypeOf('array');
 
// instance-of restriction
$slot->mustBeInstanceOf('MyServiceInterface');

提示

每次访问都获取新实例

默认情况下,容器在第二次访问后返回现有对象。但您可以通过调用Container#newInstance()方法获取每次访问的新对象。

$cart = $container['cart'];
echo 'count:' . $cart->countItems();   // count: 0
$cart->addItem('apple');
echo 'count:' . $cart->countItems();   // count: 1
 
$cart = $container['cart'];
echo 'count:' . $cart->countItems();   // count: 1
 
$cart = $container->newInstance('cart');
echo 'count:' . $cart->countItems();   // count: 0

保护组件

您可以通过使用Slot#lock()方法来保护组件。

$container['cart'] = new MyCart();
 
// lock slot
$container->slot('cart')->lock();
 
// this will fail becasue the slot is locked
$container['cart'] = new AnotherCart();     // throws SlotIsLockedException

限制组件类型

您可以通过使用Slot#mustBeTypeOf()方法来限制组件类型。

$container['something'] = new MyCart();
 
// restrict slot to array value
$container->slot('something')->mustBeTypeOf('array');
 
// this will fail because AnotherCart is not array
$container['something'] = new AnotherCart();     // throws SlotTypeRestrictionViolationException
 
// array value can be set
$container['something'] = [ 'apple', 'banana' ];

限制组件类或接口

您可以通过使用Slot#mustBeInstanceOf()方法来限制组件类或接口。

$container['something'] = new MyCart();
 
// restrict slot to array value
$container->slot('something')->mustBeInstanceOf('MyServiceInterface');
 
// this will fail because AnotherCart does not implement MyServiceInterface
$container['something'] = new AnotherCart();     // throws SlotInstanceOfRestrictionViolationException
 
// interface implemented instance can be set in this slot
$container['something'] = new MyService;        // class MyService implements MyServiceInterface

扩展组件

您可以通过使用Container#extend()方法来扩展组件。

// register my service
$container['my_service'] = new MyService();
 
// extend my serice(set max item count)
$container->extend('my_service', function($my_service) {
    $my_service->setMaxItems(10);
});

echo 'max: ' . $container['my_service']->getMaxItems();       // max: 10
 
// register array
$container['my_favorite_fruits'] = ['apple'];
 
// add banana to my favorites array
$container->extend('my_favorite_fruits', function(&$favorites) {
    $favorites[] = 'banana';
});

echo implode(', ',$container['my_favorite_fruits']);     // apple, banana

编译器配置文件格式 & 参数

编译器配置文件可以写成json、YAML和PHP格式。所有参数必须以数组元素开始。

组件配置文件:json格式示例
{
  "compiler": {
    "vendor_dir": "../vendor",
    "autoloaders": [
      "../sample_autoloader2.php"
    ]
  },
  
  "cache": {
    "root": "../cache",
    "filename": "demo_di"
  },
 
  "slots": [
    {
      "id": "david",
      "type": "object",
      "instanceOf": "\\Sample\\PersonInterface",
      "locked": true
    }
  ],
 
  "components": [
    {
      "id": "david",
      "type": "object",
      "class_name": "Sample\\Person",
      "injections": [
        {
          "new": [ "David Smith", "@int: 24", "@float: 179.2", "@func: function($target){ return 'throws '.$target.'.'; }" ]
        }
      ]
    }
  ]
}
组件配置文件:YAML格式示例
compiler:
  vendor_dir: "../vendor"
  autoloaders:
      "../sample_autoloader2.php"
  
cache:
  root: "../cache",
  filename: demo_di

slots:
  - id: david,
    type: object,
    instanceOf: \Sample\PersonInterface,
    locked: true

components:
  - id: david,
    type: object,
    class_name: Sample\Person,
    injections": 
    new: 
      - "David Smith"
      - "@int: 24"
      - "@float: 179.2"
      - "@func: function($target){ return 'throws '.$target.'.'; }"
组件配置文件:PHP格式示例
<?php
return [
    'compiler' => [
        'vendor_dir' => '../vendor',
        'autoloaders' => [ '../sample_autoloader2.php' ],
    ],
    'cache' => [
        'root' => '../cache',
        'filename' => 'demo_di',
    ],
    'slots' => [
        [
            'id' => 'david',
            'type' => 'object',
            'instanceOf' => '\Sample\PersonInterface',
            'locked' => true,
        ]
    ],
    'components' => [
        [
            'id' => 'david',
            'type' => 'object',
            'class_name' => 'Sample\Person',
            'injections' => [
                'new' => [
                    "David Smith",
                    "@int: 24",
                    "@float: 179.2",
                    "@func: function(\$target){ return 'throws '.\$target.'.'; }",
                ]
            ]        
        ]
    ],
];
组件配置文件:参数
参数 必填 说明 示例
compiler/vendor_dir 指示composer供应商目录路径 vendor_dir: "../vendor"
compiler/autoloaders 指示用户定义的自动加载器文件。在该文件中,使用spl_autoload_register全局注册您的自定义自动加载器。 autoloaders: "../my_autoloader.php"
cache/root 指示缓存目录。编译器将在此目录中输出引导PHP代码。 root: "../cache"
cache/filename 指示引导缓存代码的文件基本名称。缓存文件的完整名称将通过添加后缀'.php'生成 filename: "my_bootstrap"
slots 表示槽位数组,用于限制容器组件。参见 槽位项参数 -
组件 表示组件数组。参见 组件项参数 -
组件配置文件:槽位项参数
参数 说明 示例
id 表示槽位ID id: "my_service"
type 表示槽位类型 type: object
instanceOf 表示组件实现或继承的类或接口 instanceOf: MyServiceInterface
locked 表示槽位是否锁定。如果槽位被锁定,则无法覆盖它。 locked: true
组件配置文件:组件项参数
参数 说明 示例
id 表示组件ID id: "my_service"
type 表示组件类型 type: object
class 表示组件的类 instanceOf: MyService
injections 表示注入数组。参见 [组件注入参数](#component_injections) locked: true
组件配置文件:组件注入参数
参数 值类型 说明 示例
new array 表示构造函数注入。值将传递给构造函数 new: [ "param1", "param2" ]
method string 表示方法注入。值表示方法名。 method: doSomething
property string 表示属性注入。值表示属性名。该属性必须是公共的。 property: tax_ratio
params array 表示方法注入的参数。值必须是数组。 params: [ "pram1", "param2" ]
value int
string
bool
float
null
array
表示属性注入的值。 value: "tomato"

许可证

此库受MIT许可证的许可。

作者

stk2k

免责声明

此软件无任何保证。

我们不承担由此软件使用引起任何结果的任何责任。请自行承担责任。