我正在尝试实现Symfonys依赖项注入容器。
我设置了两个容器,一个用于数据库,另一个用于系统用户。
并且我将addArgument()
用于App
类和SystemUser
类,将SystemUser
对象推送到App
类,并且对于SystemUser
类推送Database
对象。
index.php:
require_once 'vendor/autoload.php';
use TestingDIApp;
use SymfonyComponentDependencyInjectionContainerBuilder;
use SymfonyComponentDependencyInjectionReference;
$containerBuilder = new ContainerBuilder();
$containerBuilder->register('database', 'TestingDIDatabase');
$containerBuilder->register('system.user', 'TestingDISystemUser')
->addArgument(new Reference('database'));
$containerBuilder->register('app', 'TestingDIApp')
->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 TestingDISystemUser;
class App {
public $systemUser;
public function __construct(SystemUser $systemUser)
{
var_dump($systemUser);
}
}
我确实看到了我的var_dump结果和对象,但一直收到这个错误:
PHP致命错误:Uncaught ArgumentCountError:函数TestingDI\App::__construct()的参数太少,在第28行的/www/protot/symfony di/index.PHP中传递了0,在/www/pottot/symfony di/TestingDI/App.PHP:12中正好需要1
堆栈跟踪:
0/www/potato/symfony di/index.php(28):TestingDI\App->__construct()
1{main}在第12行的/www/protot/symfony di/testingdi/App.php中抛出
这些是我的其他类:
SystemUser.php
<?php
namespace TestingDI;
use TestingDIDatabase;
class SystemUser {
public $db;
public function __construct( Database $database )
{
$this->db = $database;
}
}
数据库.php
<?php
namespace TestingDI;
class Database {
public function __construct()
{
}
}
对于什么是依赖注入以及如何使用它,似乎有一个基本的误解
由于您使用依赖容器来构建应用程序的不同部分,因此应该从容器中获取这些对象,而不是直接实例化它们。
而且,如果要直接实例化它们(例如new App()
),则需要遵守常规语言规则。在这种情况下,构造函数的签名:
public function __construct(SystemUser $systemUser)
如果您调用构造函数而不将SystemUser
类的对象传递给它,它将失败,就像您以不符合其签名的方式调用它时任何其他方法/函数都将失败一样。
当你做的时候
$app = $containerBuilder->get('app');
您的应用程序已经"初始化",您根本不需要调用new
。
这样做:
$containerBuilder = new ContainerBuilder();
$containerBuilder->register('database', 'TestingDIDatabase');
$containerBuilder->register('system.user', 'TestingDISystemUser')
->addArgument(new Reference('database'));
$containerBuilder->register('app', 'TestingDIApp')
->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容器处理什么问题的简单误解