【发布时间】:2018-05-16 04:07:30
【问题描述】:
我正在尝试将 Symfony(版本 4.0.0)中的 DependencyInjection Component 实施到我的项目中。为此,我遵循以下简单步骤,以了解autowiring 流程:
- 在
composer.json中:将命名空间App分配给src文件夹。 - 在
services.yaml中:将命名空间App分配给src文件夹。 - 在命名空间
App\Controller下的src文件夹中定义MyController类。 - 在
bootstrap.php中:创建ContainerBuilder实例($container)。 - 在
bootstrap.php中:创建一个YamlFileLoader对象并将配置文件services.yaml加载到其中。 - 在
bootstrap.php中:从$container中获取MyController的实例并将其显示在屏幕上。
但我不断收到以下错误:
( ! ) 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/
composer.json
"require": {
"php": ">=5.5.0",
"symfony/dependency-injection": "^4.0",
"symfony/config": "^4.0",
"symfony/yaml": "^4.0",
},
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
bootstrap.php
<?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);
config/services.yaml
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}'
src/Controller/MyController
<?php
namespace App\Controller;
class MyController {
public function myAction() {
echo 'Hello from MyController.';
}
}
更新 1:
使用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
我在compile() 调用之后检查了$container->definitions 数组。我意识到所有服务(包括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."
【问题讨论】:
-
查看是否可以添加 die 语句并确定 $definition->getClass() 返回的内容。尽管您的 psr-4 值似乎正确,但可能是一个简单的自动加载问题。
-
谢谢你,@Cedar。
$definition->getClass()返回NULL。对我来说,这似乎很奇怪,因为我会期望MyController的类名、实例或类似名称。我的作曲家和自动加载工作正常。我找不到丢失的部分,如果有的话。或者可能有一个错误...... -
确定在使用之前不需要 $container->compile() 吗?我一直使用框架,但从未尝试过独立使用容器。但我很确定它需要编译。
-
@Cerad 哦,那是个好主意!!! :-) 我没有太注意编译部分,因为我认为在框架之外没有必要。我是 Symfony 的新手。可惜现在为时已晚。但我明天会检查它,我一定会给你一个反馈。再次感谢你!直到明天。
-
@Cerad 嗨。我测试和调试。当容器被编译并调用
YamlFileLoader::load时,BadMethodCallException('Adding definition to a compiled container is not allowed')被抛出ContainerBuilder::setDefinition。一般来说,似乎必须在 yaml 文件中定义一个class属性。否则,ReflectionException(第 1051 行)会被一遍又一遍地抛出。我还查看了Changelog。甚至那个简单的代码示例都没有运行。我也必须定义class: ...。
标签: php symfony dependency-injection autowired