Symfony缓存反序列化时通过依赖注入补全不可序列化属性方案咨询
可行解决方案汇总(适配Symfony 5.3 + PHP 8.0环境)
方案1:将自定义ID生成器注册为Doctrine服务生成器(最优,从根源避免问题)
这是Symfony官方支持的标准用法,直接避免生成器实例被序列化到实体元数据缓存中:
- 在
config/services.yaml中给生成器打专属标签,正常注入依赖即可:
services: App\Utility\Id\Generator\SystemIdGenerator: tags: ['doctrine.id_generator'] arguments: $httpClient: '@http_client'
- 实体的CustomIdGenerator注解不需要修改,保持原类名即可。
原理:加了
doctrine.id_generator标签后,Doctrine不会自行实例化生成器,也不会将生成器实例写入元数据缓存,每次需要生成ID时会直接从Symfony容器中拉取服务实例,完全避开序列化不可序列化依赖的问题。
方案2:补全__wakeup逻辑主动拉取依赖
如果不想修改服务配置,可以直接在你现有加__sleep的方案基础上补全反序列化逻辑:
namespace App\Utility\Id\Generator; use Doctrine\ORM\Id\AbstractIdGenerator; use Symfony\Component\HttpClient\HttpClientInterface; use Symfony\Component\HttpKernel\Kernel; class SystemIdGenerator extends AbstractIdGenerator { private ?HttpClientInterface $httpClient = null; // 其他业务属性 public function __sleep(): array { // 仅返回需要序列化的业务属性,排除HttpClient return ['/* 你的业务属性名,不需要填httpClient */']; } public function __wakeup(): void { // 从全局容器直接获取HttpClient实例补全属性 $this->httpClient = Kernel::getContainer()->get('http_client'); } // 原有generate方法逻辑不需要修改 }
注意:该方案依赖Symfony全局容器,常规Web/Console请求场景无问题,特殊自定义上下文场景需要先确保内核已启动。
方案3:抽离逻辑做无依赖薄封装
将远程调用生成ID的逻辑抽为独立的单例服务SystemIdProvider,ID生成器本身不持有任何依赖,每次生成ID时临时从容器拉取服务调用:
class SystemIdGenerator extends AbstractIdGenerator { public function generate(\Doctrine\ORM\EntityManager $em, $entity) { /** @var \App\Service\SystemIdProvider $provider */ $provider = Kernel::getContainer()->get(\App\Service\SystemIdProvider::class); return $provider->getRemoteId(); } }
该方案生成器本身没有任何不可序列化属性,完全不会触发序列化告警,只是多了一层逻辑封装。
内容的提问来源于stack exchange,提问作者Gary
相关产品推荐
相关产品推荐

