PHP-DI: создать против autowire против get. Или как правильно сопоставить интерфейс с реализацией, предоставленной определением

Для моего контейнера PHP-DI в веб-MVC я подготовил следующее определение для маршрутизатора:

return [
    'router' => function (ContainerInterface $c) {
        //...

        return new Router(...);
    }
];

Теперь я хочу сопоставить интерфейс (MyLib\Routing\RouterInterface) к реализации, предусмотренной 'router' запись. В документации PHP-DI я нашел три способа достижения этого. Что-то вроде этого:

  1. RouterInterface::class => DI\create('router')
  2. RouterInterface::class => DI\autowire('router')
  3. RouterInterface::class => DI\get('router')

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

$router = $container->get(RouterInterface::class);
var_dump($router);

Но, когда я попробовал первые два варианта, я получил ошибку:

(1/1) InvalidDefinition

Entry "MyLib\Routing\RouterInterface" cannot be resolved: the class doesn't exist
Full definition:
Object (
class = #UNKNOWN# router
lazy = false
)

Поэтому я хотел бы спросить: не могли бы вы объяснить мне, в чем разница между тремя вариантами в этом случае?

Спасибо


Завершение к принятому ответу:

Ответ @MatthieuNapoli правильный. Хотя я бы завершил его следующим выводом - на основании теста, который я провел (см. Ниже).

Заключение:

Вспомогательные функции create() а также autowire() ни в коем случае не ссылаться на запись в контейнере. Они получают имя класса в качестве аргумента и проверяют, что объект этого класса НОВЫЙ (один раз). Это происходит, даже если имя существующего определения контейнера совпадает с именем класса, и даже если эта запись уже создает объект того же типа.

Исключительно вспомогательная функция get() ссылается на записи контейнера, а не на имена классов (как любезно представил Матье).

Тестовое задание:

1) я определил следующий класс:

<?php

namespace Test;

class MyTestClass {

    public function __construct($input = NULL) {
        if (empty($input)) {
            $input = 'NO INPUT';
        }

        echo 'Hello from MyTestClass. Input is: ' . $input . '<br/>';
    }

}

2) Я определил следующие записи контейнера:

return [
    'Test\MyTestClass' => function (ContainerInterface $c) {
        return new Test\MyTestClass('12345');
    },
    'my.test.entry.for.create' => DI\create('Test\MyTestClass'),
    'my.test.entry.for.autowire' => DI\autowire('Test\MyTestClass'),
    'my.test.entry.for.get' => DI\get('Test\MyTestClass'),
];

3) Я выполнил следующий код:

<?php

$myTestEntryFor_MyTestClass = $container->get('Test\MyTestClass');

$myTestEntryFor_Create = $container->get('my.test.entry.for.create');
$myTestEntryFor_Autowire = $container->get('my.test.entry.for.autowire');

/*
 * This prints nothing, because an object of type "MyTestClass" was
 * already created by the container definition "'Test\MyTestClass'".
 */
$myTestEntryFor_Get = $container->get('my.test.entry.for.get');

4) Я получил следующие результаты:

Hello from MyTestClass. Input is: 12345
Hello from MyTestClass. Input is: NO INPUT
Hello from MyTestClass. Input is: NO INPUT

1 ответ

Решение

Я приглашаю вас проверить phpdoc этих функций в functions.php.

RouterInterface::class => DI\create('router')

Это означает create router класс: этот класс PHP не существует.

RouterInterface::class => DI\autowire('router')

Это означает autowire router класс (который опять не существует).

RouterInterface::class => DI\get('router')

Это значит "когда я прошу RouterInterface::class вернуть router запись. Заметить, что get() принимает имя записи контейнера, а не имя класса.

Другие вопросы по тегам