Я изо всех сил пытаюсь заставить внедрение зависимости работать так, как я ожидаю —
Я пытаюсь внедрить класс Api, который должен знать, к какому серверу подключаться конкретному пользователю. Это означает, что переопределение свойств конструктора в файле конфигурации бесполезно, поскольку каждому пользователю может потребоваться подключиться к другому серверу.
class MyController {
private $api;
public function __construct(Api $api) {
$this->api = $api;
}
}
class Api {
private $userServerIp;
public function __construct($serverip) {
$this->userServerIp = $serverip;
}
}
Как я могу ввести этот класс с правильными параметрами? Можно ли как-то переопределить определение? Есть ли какой-нибудь способ получить класс, вызвав контейнер с параметрами?
Чтобы (надеюсь) уточнить — я пытаюсь вызвать контейнер для создания экземпляра объекта, передавая ему параметры, которые в противном случае были бы в определении.
Поскольку IP зависит от пользователя, у вас, вероятно, есть некоторая логика, которая выполняет отображение user => serverIP. Это может быть чтение из базы данных или простой шард на основе идентификатора, или что-то еще. С этой логикой вы можете построить 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);
}
}
Теперь вместо инъекций Api
в ваш контроллер вы можете ввести ApiFactory
(при условии, что ваш контроллер знает пользователя, для которого ему нужен экземпляр 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();
}
}
Я не уверен, что полностью понимаю ваш вопрос, но вы можете настроить свой Api
класс как это:
return [
'Foo' => function () {
return new Api('127.0.0.1');
},
];
Посмотрите на документацию для большего количества примеров или деталей: http://php-di.org/doc/php-definitions.html
Редактировать:
return [
'foo1' => function () {
return new Api('127.0.0.1');
},
'foo2' => function () {
return new Api('127.0.0.2');
},
];