Symfony DI: Uncaught ArgumentCountError: слишком мало аргументов для функции App :: __ construct (), 0 передано в index.php в строке 28 и ожидается ровно 1 - PullRequest
0 голосов
/ 14 января 2019

Я пытаюсь реализовать контейнер внедрения зависимостей Symfonys.

У меня установлено 2 контейнера, один для базы данных и один для пользователя системы.

и я использую "addArgument()" как для класса App, так и для класса SystemUser, выдвигая к App классу объект SystemUser и для SystemUser класса a Database объект ,

index.php:

require_once 'vendor/autoload.php';

use TestingDI\App;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

$containerBuilder = new ContainerBuilder();
$containerBuilder->register('database', '\TestingDI\Database');

$containerBuilder->register('system.user', '\TestingDI\SystemUser')
                 ->addArgument(new Reference('database'));

$containerBuilder->register('app', '\TestingDI\App')
                 ->addArgument(new Reference('system.user'));


$database       = $containerBuilder->get('database');
$systemUser     = $containerBuilder->get('system.user');
$app            = $containerBuilder->get('app');

# Initialize App class
$app = new App();

App.php:

<?php 

namespace TestingDI;

use TestingDI\SystemUser; 


class App {

    public $systemUser; 

    public function __construct(SystemUser $systemUser)
    {
        var_dump($systemUser);
    }
}

Я вижу свой результат var_dump с объектом, но продолжаю получать эту ошибку:

Неустранимая ошибка PHP: Uncaught ArgumentCountError: слишком мало аргументов для функции TestingDI \ App :: __ construct (), 0 передано в /www/potato/symfony-di/index.php в строке 28 и ровно 1 ожидается в / www / картофель / Symfony-ди / testingdi / app.php: 12

Трассировка стека:

0 /www/potato/symfony-di/index.php(28): TestingDI \ App -> __ construct ()

1 {main} добавляется в /www/potato/symfony-di/testingdi/App.php в строке 12

Это мои другие занятия:

SystemUser.php

<?php 
namespace TestingDI;

use TestingDI\Database;

class SystemUser {

    public $db; 

    public function __construct( Database $database )
    {
        $this->db = $database;
    }
}

database.php

<?php 
namespace TestingDI;

class Database {

    public function __construct()
    {

    }
}

1 Ответ

0 голосов
/ 14 января 2019

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

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

И, если вы собираетесь создавать их экземпляры напрямую (например, new App()), вы должны соблюдать правила обычного языка. В этом случае подпись конструктора:

public function __construct(SystemUser $systemUser)

Если вы вызываете конструктор, не передавая ему объект класса SystemUser, он потерпит неудачу, точно так же, как и любой другой метод / функция, произойдет сбой, если вы вызовете его способом, не соответствующим его сигнатуре .

К тому времени, как ты это сделал

$app            = $containerBuilder->get('app');

Ваше приложение уже "инициализировано", и вам вообще не нужно было звонить new.

Делая это:

$containerBuilder = new ContainerBuilder();
$containerBuilder->register('database', '\TestingDI\Database');

$containerBuilder->register('system.user', '\TestingDI\SystemUser')
                 ->addArgument(new Reference('database'));

$containerBuilder->register('app', '\TestingDI\App')
                 ->addArgument(new Reference('system.user'));


$database       = $containerBuilder->get('database');
$systemUser     = $containerBuilder->get('system.user');
$app            = $containerBuilder->get('app');

Вы делали эквивалент:

$database   = new Database();
$systemUser = new SystemUser($database);
$app        = new App($systemUser);

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

Но вы можете позволить мощности autowiring сделать большую часть тяжелой работы за вас и сделать следующее:

$container = new ContainerBuilder();
$container->autowire( Database::class );
$container->autowire( SystemUser::class );
$container->autowire( App::class )
          ->setPublic( true );

$container->compile();

// this will get you an application instance with all the dependencies
// resolved and injected in the class.
$app = $container->get( App::class );

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

...