Инъекция зависимостей Laravel с наследованием

Допустим, у меня такой случай:

<?php

abstract class Service {

    protected $config;

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

class ClientService extends Service {

}

class ProductService extends Service {

}

Можно ли зарегистрировать у моего поставщика услуг внедрение зависимостей для абстрактного родительского класса моих услуг?

У меня есть API, который динамически создается из спецификации, и каждый из этих классов должен расширять abstract Service, чтобы он мог наследовать основные функции.

Как я могу внедрить зависимости в свою абстрактную службу при создании экземпляра дочерней службы?


РЕДАКТИРОВАТЬ: Этот вопрос был специально задан для внедрения абстрактного класса без возможности привязки дочерних классов, которые создаются автоматически.


person kitensei    schedule 18.06.2015    source источник


Ответы (2)


В вашем примере вам нужно вручную передавать объект config каждый раз, когда вы создаете экземпляр из класса Service или дочернего класса.

Поэтому, если вы хотите напрямую создать дочернюю службу, вы можете использовать что-то вроде $cs = new ClientService(new Config());

Однако вы можете использовать реальное преимущество DI (поскольку вы используете Laravel), указав имя класса в конструкторе, как показано ниже.

public function __construct(\Config $config)

Таким образом, если вы не передадите параметр при создании экземпляра, он по умолчанию создаст объект класса с подсказкой типа и внедрит его. Таким образом, вы могли бы использовать это как.

$cs = new ClientService();

Это добавит экземпляр Laravel Config в объект ClientService.

person blackpla9ue    schedule 18.06.2015
comment
Итак, у меня нет реального способа ввести более конкретный код в абстрактный класс? Я должен придерживаться автоматического DI из laravel в этом конкретном случае? - person kitensei; 18.06.2015
comment
Да, но хорошо, что если вы используете этот класс в другом месте, у вас есть возможность вручную передать любой config экземпляр, который у вас может быть. Вы всегда можете сделать ClientService(new SomeOtherConfig()); - person blackpla9ue; 18.06.2015

Здесь вы можете сделать две вещи. Во-первых, если $config - это класс, вы можете ввести подсказку в абстрактном классе:

abstract class Service {

    protected $config;

    public function __construct(ClassName $config)
    {
        $this->config = $config;
    }
}

Затем каждый раз, когда дочерние классы разрешаются посредством инъекции или путем вызова App::make('ClientService'), будет внедрен класс конфигурации.

Если конфигурация не является классом и не может быть указана на тип, вам придется привязать дочерние классы к контейнеру индивидуально:

App::bind('ClientService', function () {
    // Get $config from somewhere first

    return new ClientService($config);
});

App::bind('ProductService', function () {
    // Get $config from somewhere first

    return new ProductService($config);
});

После этого вы сможете позвонить App::make('ClientService') или разрешить проблему через DI.

person James Flight    schedule 18.06.2015
comment
Действительно, я думал об этом, но хотел бы избежать, потому что классы обслуживания генерируются из спецификации с помощью задачи cron, поэтому (этого не должно происходить, но кто знает) можно добавить какой-то класс, и мне придется обновить свои поставщик услуг вручную - person kitensei; 18.06.2015
comment
Неужели это не остановит работу первого варианта? - person James Flight; 18.06.2015
comment
конечно, я думаю, что это то, что я буду делать, я выберу другой ответ, так как он отвечал на мой случай раньше вашего - person kitensei; 18.06.2015