2

我正在尝试实现 Symfonys 依赖注入容器。

我设置了 2 个容器,一个用于数据库,一个用于系统用户。

而且我正在使用addArgument()AppSystemUser类,将对象推送到类,并将对象App推送到类。SystemUserSystemUserDatabase

索引.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();

应用程序.php:

<?php 

namespace TestingDI;

use TestingDI\SystemUser; 


class App {

    public $systemUser; 

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

我确实看到了带有对象的 var_dump 结果,但不断收到此错误:

PHP 致命错误:未捕获的 ArgumentCountError:函数 TestingDI\App::__construct() 的参数太少,在第 28 行的 /www/potato/symfony-di/index.php 中传递了 0,而 /www/potato/symfony 中预期的正是 1 -di/testingdi/App.php:12

堆栈跟踪:

0 /www/potato/symfony-di/index.php(28): 测试DI\App->__construct()

1 {main} 在第 12 行的 /www/potato/symfony-di/testingdi/App.php 中抛出

这些是我的其他课程:

系统用户.php

<?php 
namespace TestingDI;

use TestingDI\Database;

class SystemUser {

    public $db; 

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

数据库.php

<?php 
namespace TestingDI;

class Database {

    public function __construct()
    {

    }
}
4

1 回答 1

6

关于什么是依赖注入以及如何使用它似乎存在一个基本的误解。

由于您使用依赖容器来构建应用程序的不同部分,因此您应该从容器中获取这些对象,而不是直接实例化它们。

而且,如果您要直接实例化它们(例如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 容器为您完成工作。当然,考虑到您的容器定义有多冗长,这似乎毫无意义。

但是您可以让自动装配的力量为您完成大部分繁重的工作,并执行以下操作:

$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 容器处理什么问题的简单误解。

于 2019-01-14T14:38:12.797 回答