【问题标题】:Symfony 4: DependencyInjection Component - Uncaught ReflectionException: Class does not existSymfony 4:DependencyInjection 组件 - 未捕获的 ReflectionException:类不存在
【发布时间】: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-&gt;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-&gt;definitions 数组。我意识到所有服务(包括App\Controller\MyController)都保存在compile()之前的定义列表中,编译过程从数组中删除了这些服务。

更多:在$compiler-&gt;passConfig-&gt;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-&gt;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


【解决方案1】:

我继续设置了一个新项目。

您的设置存在两个问题。

首先你需要在使用之前编译容器:

// 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

这基本上就是框架所做的。

【讨论】:

  • 难以置信,你真的做到了!!! :-))) 确实有效!!!!.. 我必须说,雪松,你的毅力给我留下了深刻的印象!为了找到答案,我花了好几个小时......而且可能你也花了很多时间来完成这项任务,以帮助我。你让我开心,我感谢你的耐心!在接下来的 3 天里,请接受我的 150 多份礼物 :-) 祝您有愉快的一天,我希望再次阅读您的答案。怀着感激之情。 P.S:抱歉迟到了,但我从 25 分钟前开始写这条消息 :-)) 再见
  • 没问题,但谢谢。我实际上是在等待大学橄榄球比赛开始。反射错误对我来说是新的,所以我想追踪它,特别是因为 S4 刚刚发布。我应该通过更仔细地阅读您的问题来了解公共/私人问题。
  • 哦,相信我,我会很乐意的。而且,好吧,为新 S4 打进几个球! :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-30
  • 2021-12-10
  • 1970-01-01
  • 2020-01-03
  • 2018-01-03
  • 2015-01-12
  • 2014-01-24
相关资源
最近更新 更多