编译时报
Class Vendor\Module\Model\SomethingFactory does not exist,很多人的第一反应是删除
generated
再编译。这个办法只对“生成目录不可写或旧代码残留”有效。如果源类名称、命名空间或
Composer
自动加载本身就有问题,清十次生成目录也不会好。先分清报错的是“应该由
Magento 生成的 Factory”,还是“项目里本来就该存在的普通类”。
先去掉Factory后缀,确认源类能被自动加载
例如报错是:
Class Vendor\Catalog\Model\FeedFactory does not exist
Magento 能生成 FeedFactory 的前提是
Vendor\Catalog\Model\Feed 可以被 Composer
找到。依次检查:
test -f app/code/Vendor/Catalog/Model/Feed.php && echo found
php -l app/code/Vendor/Catalog/Model/Feed.php
composer dump-autoload -o
php -r "require 'app/bootstrap.php'; var_dump(class_exists('Vendor\\Catalog\\Model\\Feed'));"
最后一条如果返回 false,问题还没到代码生成阶段。检查文件名大小写、namespace、类名以及模块是否真的存在。Linux 区分大小写,本地 macOS 能跑不代表服务器也能加载。
连续大写缩写最容易让文件名和类名对不上
像 WeatherDataDBDetails
这种命名,看起来没有拼错,但文件、类型声明、构造参数和引用处只要有一处写成
WeatherDataDbDetails,开发机上可能侥幸通过,Linux
编译就会失败。不要靠肉眼来回看,直接搜索所有声明和引用:
rg -n 'WeatherData(DB|Db)Details' app/code
比较稳的做法是按项目约定统一缩写写法,例如把 DB 当作
Db,然后让文件名、类名、use、XML
和构造参数完全一致。修改大小写时,Git
在不区分大小写的文件系统上可能不记录变化,可以通过中间文件名完成
rename。
源类能加载,再查generated目录的属主和残留
Magento 2.2 及以后通常在 generated/code 生成
Factory、Proxy 和 Interceptor。先看运行编译的用户是否有权限:
id
namei -l generated/code
find generated/code -maxdepth 3 ! -user deploy -ls | head
不要直接
chmod -R 777 generated。应该让固定的部署用户拥有目录,并让
Web 用户按部署模型获得需要的读取权限。确认当前没有其他发布或 PHP
进程正在生成代码后,再清理旧产物并重新编译:
find generated/code generated/metadata -mindepth 1 -delete
php bin/magento setup:di:compile
如果报错类属于已经卸载的模块,查配置和缓存残留
第三方模块从 Composer
移除后,app/etc/config.php、其他模块的
di.xml、插件声明或编译缓存可能仍引用旧类。用完整类名搜索代码和配置:
rg -n 'OldVendor\\OldModule|OldClass' app/code app/etc vendor composer.*
确认模块确实已卸载后,修正模块列表和依赖,再按当前环境清配置缓存。Redis
是共享缓存时只删除本项目使用的 cache database 或 key
前缀,不要在一台承载多个站点的 Redis 上随手 FLUSHALL。
最终判断很直接:源类 class_exists() 为
true、生成目录可写、旧模块引用已清干净,setup:di:compile
才有可能稳定通过。Factory
不存在只是结果,真正要修的是它为什么没法被生成。

