Silex 2.3.0搭配Symfony4.4报错:Call to a member function has() on null
我们有一个基于Silex 2.2.5分支与Symfony 3.4的大型旧应用,计划迁移出Silex,但目前仍在多工程师协作开发中。为在PHP7.4于2022年11月停止支持前升级到PHP8.1,我们将依赖升级至Silex 2.3.0与Symfony4.4,过程无问题,但页面加载时出现致命错误:PHP Fatal error: Uncaught Error: Call to a member function has() on null in /var/task/vendor/symfony/http-kernel/EventListener/SessionListener.php:41
该错误来自Symfony4.4新增的onKernelRequest方法,调试发现$this->container为null,且SessionListener的构造函数未被调用。临时移除该方法后站点可正常运行,但这并非可行方案。我们查阅Silex文档未找到适配Symfony4.4的额外要求,搜索得知可能需通过services.yml注入容器依赖,但项目无此文件,现寻求解决思路,是否有成功运行Silex2.3.0与Symfony4.4的案例?
完整错误栈信息
result = {array} [9] 0 = {array} [7] file = "/var/task/vendor/symfony/event-dispatcher/EventDispatcher.php" line = {int} 264 function = "onKernelRequest" class = "Symfony\Component\HttpKernel\EventListener\SessionListener" object = {OurCompany\Session\SessionListener} [3] type = "->" args = {array} [3] 1 = {array} [7] file = "/var/task/vendor/symfony/event-dispatcher/EventDispatcher.php" line = {int} 239 function = "doDispatch" class = "Symfony\Component\EventDispatcher\EventDispatcher" object = {Symfony\Component\EventDispatcher\EventDispatcher} [3] type = "->" args = {array} [3] 2 = {array} [7] file = "/var/task/vendor/symfony/event-dispatcher/EventDispatcher.php" line = {int} 73 function = "callListeners" class = "Symfony\Component\EventDispatcher\EventDispatcher" object = {Symfony\Component\EventDispatcher\EventDispatcher} [3] type = "->" args = {array} [3] 3 = {array} [7] file = "/var/task/vendor/symfony/http-kernel/HttpKernel.php" line = {int} 135 function = "dispatch" class = "Symfony\Component\EventDispatcher\EventDispatcher" object = {Symfony\Component\EventDispatcher\EventDispatcher} [3] type = "->" args = {array} [2] 4 = {array} [7] file = "/var/task/vendor/symfony/http-kernel/HttpKernel.php" line = {int} 81 function = "handleRaw" class = "Symfony\Component\HttpKernel\HttpKernel" object = {Symfony\Component\HttpKernel\HttpKernel} [4] type = "->" args = {array} [2] 5 = {array} [7] file = "/var/task/vendor/silex/silex/src/Silex/Application.php" line = {int} 496 function = "handle" class = "Symfony\Component\HttpKernel\HttpKernel" object = {Symfony\Component\HttpKernel\HttpKernel} [4] type = "->" args = {array} [3] 6 = {array} [7] file = "/var/task/vendor/silex/silex/src/Silex/Application.php" line = {int} 477 function = "handle" class = "Silex\Application" object = {OurCompany\Application} [9] type = "->" args = {array} [1] 7 = {array} [7] file = "/var/task/lib/Application.php" line = {int} 37 function = "run" class = "Silex\Application" object = {OurCompany\Application} [9] type = "->" args = {array} [1] 8 = {array} [7] file = "/var/task/web/index.php" line = {int} 43 function = "run" class = "OurCompany\Application" object = {OurCompany\Application} [9] type = "->" args = {array} [1]
解决思路
1. 修正自定义SessionListener的注册与依赖注入
从错误栈可见,实际执行的是OurCompany\Session\SessionListener而非Symfony原生类,说明你们自定义了SessionListener。Symfony4.4的原生SessionListener构造函数要求注入ContainerInterface,如果自定义类继承了它,必须确保:
- 自定义类的构造函数正确接收并传递容器参数给父类
- 在Silex中注册该服务时注入容器实例
示例注册代码:
$app['session.listener'] = function ($app) { return new OurCompany\Session\SessionListener($app); };
2. 兼容Symfony4.4的SessionListener逻辑改动
若自定义Listener不需要Symfony4.4新增的onKernelRequest逻辑,可以直接重写该方法,避免调用容器相关代码;若需要保留新逻辑,必须保证容器被正确注入。
3. 手动配置服务(无需services.yml)
Silex支持纯代码配置服务,无需依赖services.yml。在应用初始化阶段,确保SessionListener服务被正确定义:
use OurCompany\Session\SessionListener; use Symfony\Component\DependencyInjection\ContainerInterface; $app->register(new Silex\Provider\SessionServiceProvider()); // 覆盖默认的session listener服务 $app['session.listener'] = function (ContainerInterface $container) { return new SessionListener($container); };
4. 排查服务冲突
检查项目中其他自定义服务、事件订阅者的注册方式,确保它们符合Symfony4.4的依赖注入规范,避免出现容器未正确传递的情况。
关于兼容性案例
确实有团队成功运行Silex 2.3.0 + Symfony4.4,核心是确保所有依赖容器的服务(如事件监听器)在注册时都正确注入容器实例,适配Symfony4.4的组件改动。
内容的提问来源于stack exchange,提问作者Aaryn

