简体   繁体   English

使用PHP-DI将参数注入构造函数

[英]Injecting parameters into constructor with PHP-DI

I am struggling to get dependency injection to work the way I expect - 我正在努力让依赖注入以我期望的方式工作 -

I am trying to inject a class, Api, which needs to know which server to connect to for a particular user. 我试图注入一个类Api,它需要知道特定用户要连接到哪个服务器。 This means that overriding constructor properties in a config file is useless, as each user may need to connect to a different server. 这意味着在配置文件中覆盖构造函数属性是无用的,因为每个用户可能需要连接到不同的服务器。

class MyController {
    private $api;

    public function __construct(Api $api) {
        $this->api = $api;
    }
}

class Api {
     private $userServerIp;

     public function __construct($serverip) {
         $this->userServerIp = $serverip;
     }
}

How can I inject this class with the correct parameters? 如何为此类注入正确的参数? Is it possible to override the definition somehow? 是否可以以某种方式覆盖该定义? Is there some way of getting the class by calling the container with parameters? 有没有办法通过调用具有参数的容器来获取类?

To (hopefully) clarify - I'm trying to call the container to instantiate an object, while passing to it the parameters that would otherwise be in a definition. (希望)澄清 - 我正在尝试调用容器来实例化一个对象,同时向它传递否则将在定义中的参数。

Since IP depends on the user you probably have some piece of logic that does the user=>serverIP mapping. 由于IP取决于用户,因此您可能拥有执行user => serverIP映射的一些逻辑。 It might be reading from the db or simple id-based sharding, or whatever. 它可能正在从数据库中读取或基于简单的基于ID的分片,或任何其他内容。 With that logic you can build ApiFactory service that creates Api for a particular user: 使用该逻辑,您可以构建ApiFactory服务,为特定用户创建Api

class ApiFactory {

    private function getIp(User $user) {
        // simple sharding between 2 servers based on user id
        // in a real app this logic is probably more complex - so you will extract it into a separate class

        $ips = ['api1.example.com', 'api2.example.com'];
        $i = $user->id % 2;
        return $ips[$i];
    }

    public function createForUser(User $user) {
        return new Api($this->getIp($user);
    }
}

Now instead of injecting Api into your controller you can inject ApiFactory (assuming your controller knows the user for which it needs the Api instance) 现在,可以将ApiFactory注入(而不是将Api注入到控制器中)(假设您的控制器知道需要Api实例的用户)

class MyController {
    private $apiFactory;

    public function __construct(ApiFactory $apiFactory) {
        $this->apiFactory = $apiFactory;
    }

    public function someAction() {
        $currentUser = ... // somehow get the user - might be provided by your framework, or might be injected as well
        $api = $this->apiFactory->createForUser($currentUser);
        $api->makeSomeCall();
    }
}

I am not sure I understand your question fully, but you can configure your Api class like this: 我不确定我完全理解你的问题,但你可以像这样配置你的Api类:

return [
    'Foo' => function () {
        return new Api('127.0.0.1');
    },
];

Have a look at the documentation for more examples or details: http://php-di.org/doc/php-definitions.html 请查看文档以获取更多示例或详细信息: http : //php-di.org/doc/php-definitions.html


Edit: 编辑:

return [
    'foo1' => function () {
        return new Api('127.0.0.1');
    },
    'foo2' => function () {
        return new Api('127.0.0.2');
    },
];

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM