我正在尝试将Symfony(版本4.0.0)中的DependencyInjection Component实现到我的项目中。为此,我按照以下简单步骤来理解autowiring过程:
composer.json
中:将名称空间App
分配到src
文件夹。services.yaml
中:将名称空间App
分配到src
文件夹。MyController
下的src
文件夹中定义App\Controller
类。bootstrap.php
中:创建ContainerBuilder
个实例($container
)。bootstrap.php
中:创建一个YamlFileLoader
对象并将配置文件services.yaml
加载到其中。bootstrap.php
中:从MyController
获取$container
的实例并在屏幕上显示。但我一直收到以下错误:
( ! ) Fatal error: Uncaught ReflectionException: Class does not exist in <path-to-my-project-root>/vendor/symfony/dependency-injection/ContainerBuilder.php on line 1051
( ! ) ReflectionException: Class does not exist in <path-to-my-project-root>/vendor/symfony/dependency-injection/ContainerBuilder.php on line 1051
Call Stack
# Time Memory Function Location
1 0.0160 354632 {main}( ) .../index.php:0
2 0.0166 357928 require_once( '<path-to-my-project-root>/bootstrap.php' ) .../index.php:7
3 0.0872 1752040 Symfony\Component\DependencyInjection\ContainerBuilder->get( ) .../bootstrap.php:16
4 0.0872 1752040 Symfony\Component\DependencyInjection\ContainerBuilder->doGet( ) .../ContainerBuilder.php:522
5 0.0872 1752816 Symfony\Component\DependencyInjection\ContainerBuilder->createService( ) .../ContainerBuilder.php:555
6 0.0873 1752928 __construct ( ) .../ContainerBuilder.php:1051
ContainerBulder::createService
方法中此行(1051)发生错误,因为$definition->getClass()
返回NULL
:
private function createService(Definition $definition, array &$inlineServices, $id = null, $tryProxy = true) {
// Line 1051:
$r = new \ReflectionClass($class = $parameterBag->resolveValue($definition->getClass()));
//..
}
在Automatic Service Loading in services.yaml一章中,据我所知,只使用services.yaml
中没有任何其他设置的设置,DI容器将知道如何创建MyController
的实例。也许我错了?...
请你花一点时间来帮助我?非常感谢你。
我的项目包含以下结构和文件:
bootstrap.php
composer.json
config/
services.yaml
src/
Controller/
MyController
vendor/
symfony/
config/
dependency-injection/
filesystem/
polyfill-mbstring/
yaml/
"require": {
"php": ">=5.5.0",
"symfony/dependency-injection": "^4.0",
"symfony/config": "^4.0",
"symfony/yaml": "^4.0",
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
<?php
use App\Controller\MyController;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
require '../vendor/autoload.php';
$container = new ContainerBuilder();
$fileLocator = new FileLocator(__DIR__ . '/config');
$loader = new YamlFileLoader($container, $fileLocator);
$loader->load('services.yaml');
$myController = $container->get(MyController::class);
var_dump($myController);
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
public: false # Allows optimizing the container by removing unused services; this also means
# fetching services directly from the container via $container->get() won't work.
# The best practice is to be explicit about your dependencies anyway.
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/*'
exclude: '../src/{Entity,Migrations,Tests}'
<?php
namespace App\Controller;
class MyController {
public function myAction() {
echo 'Hello from MyController.';
}
}
使用compile()
$loader->load('services.yaml');
$container->compile();
我收到以下错误:
( ! ) Fatal error: Uncaught Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException: You have requested a non-existent service "App\Controller\MyController". in <my-project-path>/vendor/symfony/dependency-injection/ContainerBuilder.php on line 950
( ! ) Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException: You have requested a non-existent service "App\Controller\MyController". in <my-project-path>/vendor/symfony/dependency-injection/ContainerBuilder.php on line 950
Call Stack
# Time Memory Function Location
1 0.1512 357648 {main}( ) .../index.php:0
2 0.1675 361056 require_once( '<my-project-path>/bootstrap.php' ) .../index.php:7
3 3.5621 2582624 Symfony\Component\DependencyInjection\ContainerBuilder->get( ???, ??? ) .../bootstrap.php:18
4 3.5621 2582624 Symfony\Component\DependencyInjection\ContainerBuilder->doGet( ???, ???, ??? ) .../ContainerBuilder.php:522
我在$container->definitions
电话后检查了compile()
数组。我意识到所有服务(包括App\Controller\MyController
)都保存在compile()
之前的定义列表中,并由编译过程从数组中删除。
更多内容:在$compiler->passConfig->log
中我找到了这些条目(在编译步骤之后):
[0] string "Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Psr\Container\ContainerInterface"; reason: private alias."
[1] string "Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\DependencyInjection\ContainerInterface"; reason: private alias."
[2] string "Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass: Inlined service "App\Service\MyService" to "App\Controller\MyController"."
[3] string "Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "App\Controller\MyController"; reason: unused."
[4] string "Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass: Removed service "App\Service\MyService"; reason: unused."
答案 0 :(得分:5)
我继续设置一个新项目。
您的设置存在两个问题。
首先,您需要在使用之前编译容器:
// bootstrap.php
$loader->load('services.yaml');
$container->compile();
$myController = $container->get(MyController::class);
然后,您需要先将控制器服务公开,然后再将其从容器中拉出来:
// services.yaml
App\:
resource: 'src/*'
exclude: 'src/{Entity,Migrations,Tests}'
App\Controller\:
resource: 'src/Controller/*'
public: true
这基本上就是框架的作用。