nucleuslabs/dependency-injector

v0.1.6 2016-11-25 00:43 UTC

This package is auto-updated.

Last update: 2020-08-14 09:58:13 UTC


README

与其他依赖注入器不同,这不是一个DI容器。它为您调用方法,用任何缺失的参数填充,而不是强迫您手动从容器中取出。

概述

零配置

$di = new DependencyInjector();
$di->construct(\DateTime::class); // constructs a new DateTime object using default parameters (i.e. current time)
$di->call('time'); // calls time()

不激动人心吗?真正的魔法发生在您使用类型提示参数时

class MyController {
    private $req;

    public function __construct(Request $req) {
        dump(__METHOD__, $req);
        $this->req = $req;
    }

    public function action(Response $res) {
        dump(__METHOD__, $res);
    }
}

class Request {
    private $uri;

    public function __construct(Uri $uri) {
        dump(__METHOD__, $uri);
        $this->uri = $uri;
    }
}

class Response {
    
}

class Uri {
    private $uriParts;

    public function __construct($uriString = null) {
        dump(__METHOD__, $uriString);
        if(!strlen($uriString)) {
            $this->uriParts = parse_url('http://username:password@hostname:9090/path?arg=value#anchor'); // TODO: get from $_REQUEST
        } else {
            $this->uriParts = parse_url($uriString);
        }
    }
}

$di = new \mpen\DI\DependencyInjector();
$di->call('\MyController::action');

这是它所做的事情

  1. 尝试调用 \MyController::action
  2. 注意到 \MyController::action 是非静态的,所以它尝试构造一个新的 MyController
  3. MyController 需要一个 Request,所以它尝试创建一个
  4. Request 需要一个 Uri
  5. Uri 需要 $uriString,但我们没有提供,所以它使用默认值(null
  6. 现在我们有了完全实例化的 MyController,我们可以调用 ->action(),但它需要一个 Response
  7. 构造一个 Response 并调用方法

如果还不清楚,下面是输出结果

Uri::__construct"
null

"Request::__construct"
Uri {#18
  -uriParts: array:8 [
    "scheme" => "http"
    "host" => "hostname"
    "port" => 9090
    "user" => "username"
    "pass" => "password"
    "path" => "/path"
    "query" => "arg=value"
    "fragment" => "anchor"
  ]
}

"MyController::__construct"
Request {#14
  -uri: Uri {#18
    -uriParts: array:8 [
      "scheme" => "http"
      "host" => "hostname"
      "port" => 9090
      "user" => "username"
      "pass" => "password"
      "path" => "/path"
      "query" => "arg=value"
      "fragment" => "anchor"
    ]
  }
}

"MyController::action"
Response {#7}

注册全局变量

在上面的例子中,如果我们有一个URI并想用这个而不是默认值,我们可以在应用生命周期的早期注册它

$di->registerGlobal('uriString', 'http://example.com:3000');

然后每次遇到名为 $uriString 的参数而没有其他值提供时,它将检查全局变量中是否存在,并使用它而不是默认值!

如果您想将 $_GET 和/或 $_POST 变量注册为全局变量,以便将它们用作控制器操作的默认值,例如(如果您使用MVC),则可以这样做。

注册类

或者,您也可以注册一个类

$di->registerObject(new Uri('http://google.com'));

现在当 DependencyInjector 遇到 Uri 时,它将使用您注册的实例,而不是尝试自己构造一个。

注册回调

如果您不想在需要之前实例化对象,并且想完全控制其创建方式,您可以注册一个回调

$di->registerCallback(Uri::class, function() {
    return new Uri('https://bing.com');
});

注册接口

如果您的函数针对接口进行了类型提示,DI将如何知道要替换哪个类?为此,您可以注册一个接口!

$di->registerInterface(\Psr\Http\Message\RequestInterface::class, \GuzzleHttp\Psr7\Request::class);

请注意,您也可以使用此方法注册抽象类和继承类。

名称匹配

如果您不使用单例,怎么办?例如,如果您有两个不同的数据库连接?您可以使用 $namePatt 选项来注册它们,以便在参数名称与正则表达式模式匹配时注入。

$di->registerObject($appDb, '~app(?!\\p{Ll})~A');
$di->registerObject($pcsDb, '~pcs(?!\\p{Ll})~A');

现在当函数参数以 "app" 开头时,将提供 $appDb,当参数以 "pcs" 开头时,将提供 $pcsDb

如果两个模式都不匹配,DI将像通常一样尝试自己构造数据库对象,这可能会失败,因为它不知道您的DSN。

如果您不希望发生这种情况,您始终可以 $di->registerCallback(YourDB::class, ...) 作为后备选项。在这种情况下,您可能只想抛出一个异常。虽然这个DI很强大,但它不能黑客您的数据库并从空中窃取您的凭据 :-)

更多...

查看单元测试以获取更多示例。

选项

选项类型默认描述
cacheObjectsbooltrue为未来重用缓存构造的对象
全局变量数组[]全局关键字参数(如果参数名匹配则自动注入)
memoizeFunctionsbooltrue未实现
memoizeMethodsboolfalse未实现
coercePosArgsbooltrue如果位置参数不匹配,则隐式转换为正确的类型
coerceKwArgsbooltrue如果关键字参数不匹配,则隐式转换为正确的类型
coerceGlobalsboolfalse如果全局变量不匹配,则隐式转换为正确的类型
coerceCallback可调用construct如果没有为特定类型注册回调,则用于强制转换的默认函数。如果未提供,将尝试使用构造函数,传入一个位置参数。
propagateKwArgsboolfalse匹配关键字参数与顶层调用(false)还是递归构造依赖项(true)?

许可证

MIT.