直接删tests/目录会报class not found,因为某些包(如旧版monolog/monolog)将streamhandler示例代码放在tests/下,且其autoload配置明确声明了该路径;php autoloader严格按映射加载,删除后即失效。

直接删tests/目录为什么报Class not found
因为某些包(比如旧版monolog/monolog)把StreamHandler的示例实现放在tests/下,且其autoload配置里真写了这条路径。PHP autoloader 会按映射去加载,删了就找不到类。
这不是个别现象——只要包作者在composer.json的autoload或autoload-dev里声明了tests/,它就是运行时依赖的一部分。
- 别用
find vendor -name tests -type d -exec rm -rf {} +,这是暴力扫雷,不是清理 -
tests/是否可删,得看它是否出现在vendor/composer/autoload_*.php的映射里 - 手动删前,先跑
composer dump-autoload --classmap-authoritative -o,再检查autoload_classmap.php里还有没有tests/路径
archive.excludes配置只对zip包生效,且路径必须带前导斜杠
这个配置控制的是解压阶段的行为,只影响从 Packagist 下载的 dist(zip)包,对 git clone 的 source 方式完全无效。
常见错误是写成"tests"或"Tests",结果不匹配——必须写"/tests/",开头斜杠表示“从包根开始匹配”。
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
- 正确写法:
"archive": {"excludes": ["/tests/", "/docs/", "/examples/", "/.github/"]} - 错误写法:
"tests"、"**/tests/**"(插件不支持 glob)、"vendor/tests"(插件自动作用于每个包内部,不用加vendor/前缀) - 配置后必须执行
composer install或composer update才会触发,已有文件不会被自动清理
--no-dev和--prefer-dist不能替代archive.excludes
--no-dev只跳过require-dev声明的包,不影响已安装包内部的tests/目录;--prefer-dist只是优先下载 zip 包,但有些作者打包时仍把tests/塞进 zip 里——这时候就得靠archive.excludes兜底。
-
--no-dev:省掉几百 MB 的 dev 包(如phpunit、phpstan) -
--prefer-dist:避免 git clone 带来的.git目录和完整历史 -
--remove-vcs:兜底删掉 zip 包里残留的.git目录(某些包打包不规范) - 三者必须配合
rm -rf vendor && composer install才生效,update不重建文件结构
--classmap-authoritative才是瘦身生效的关键
前面所有操作只是“删文件”,但如果 autoloader 还在遍历整个vendor/找类,删了tests/也可能因扫描失败而挂——尤其在容器、NFS 或只读文件系统上。
这步不减体积,但决定前面所有动作会不会白做。
- 确保
composer.json中已设"optimize-autoloader": true - 运行
composer dump-autoload --optimize --classmap-authoritative --no-dev - 后续
composer install --no-dev --optimize-autoloader --classmap-authoritative会重建vendor/,且只保留autoload_classmap.php里登记的路径 - 如果用了 OPcache,记得调用
opcache_reset(),否则 PHP 可能还在用旧映射










