简体   繁体   中英

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. 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. It might be reading from the db or simple id-based sharding, or whatever. With that logic you can build ApiFactory service that creates Api for a particular user:

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)

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:

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


Edit:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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