最稳妥方式是封装成独立PHP类(如src/Scripts/GenerateEntity.php),在composer.json中通过"generate:entity": "php scripts/generate-entity.php"调用;避免JSON内嵌逻辑、exec调用及裸路径操作,优先使用vendor/bin下基于symfony/console等的标准CLI脚本。

Composer脚本里怎么调用 PHP 代码生成文件
直接在 composer.json 的 scripts 里写 PHP 逻辑,最稳妥的方式是封装成独立函数或类,再通过 php 命令调用。别把大段生成逻辑塞进 JSON 字符串里——转义麻烦、调试困难、无法复用。
- 推荐做法:写一个
generate:entity类,放在src/Scripts/GenerateEntity.php,然后在composer.json中注册为命令式脚本:"generate:entity": "php scripts/generate-entity.php" - 避免用
exec()或shell_exec()在脚本里再起 shell 进程,容易因路径、权限、PHP CLI 配置不一致出错 - 注意
composer install和composer run-script的工作目录默认是项目根目录,但某些 IDE 或 CI 环境会切换 cwd,建议在脚本开头用chdir(dirname(__DIR__))显式锚定
为什么 vendor/bin 目录下的可执行脚本比 composer.json scripts 更可靠
因为它们走的是标准的 PSR-4 自动加载 + CLI 入口流程,有完整的依赖注入、异常捕获和参数解析能力,不像 scripts 那样受限于 JSON 字符串解析和 shell 执行环境。
-
vendor/bin下的脚本(比如用symfony/console写的)能自然支持--help、-v、选项校验、交互式输入,而scripts只能靠$argv手动解析 - 常见错误:
"scripts": {"gen": "php generate.php --type=user"}—— 这里的--type=user不会被 Composer 透传给 PHP 脚本,实际收到的是空$argv,除非你用composer run-script gen -- --type=user(注意双横杠) - 性能上没差别,但维护性差很多:每次改参数就得改两处(JSON + 脚本),而
vendor/bin脚本改完即生效
模板生成时路径和命名空间对不上怎么办
绝大多数“生成了文件但 autoload 找不到”的问题,根源不在生成逻辑,而在 composer.json 的 autoload 配置没同步更新,或者生成路径没对齐 PSR-4 规则。
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
- 生成类文件前,先确认目标路径是否属于已声明的 autoload namespace,例如
"App\Generators\": "src/Generators/",那生成的文件就必须放在src/Generators/UserGenerator.php,且命名空间必须是AppGenerators - 别用
file_put_contents('User.php', $code)这种裸路径——它不保证目录存在,应改用mkdir(..., 0755, true)+file_put_contents($fullPath, $code) - Windows 下注意路径分隔符:
str_replace('/', DIRECTORY_SEPARATOR, $path)不够,要用realpath()或Path::canonicalize()(来自symfony/filesystem)
如何让生成脚本支持 --dry-run 和 --force 参数
硬编码判断 $argv 容易漏边界情况,建议用轻量库如 symfony/console 或至少用 getopt() 解析,否则用户输错参数格式就会静默失败。
-
--dry-run不是只 echo 文件名,要真实模拟所有 IO 操作:检查目标文件是否存在、是否可写、模板能否读取、命名空间是否合法,最后才汇总输出“将创建 X 个文件” -
--force的语义必须明确:是覆盖已有文件?还是跳过冲突检测?建议默认不覆盖,加--force后才 unlink() 原文件,避免误删 - 别忽略 umask 和文件权限:生成的 PHP 文件应该设为
0644,可执行脚本才是0755;否则某些共享主机或 CI 环境会报“Permission denied”
真正难的不是写生成逻辑,而是让每次生成都符合当前项目的 autoloading 约束、目录规范和团队命名习惯——这些没法靠模板变量解决,得靠脚本启动时主动读取 composer.json 里的 autoload 配置来动态适配。


















