composer scripts需在特定事件(如install/update)或手动调用时生效,不自动运行;关键初始化应绑定post-install-cmd和post-update-cmd,并文档注明手动执行;支持参数需通过环境变量或php文件实现;避免在post-autoload-dump中做耗时操作;script名称须加前缀防冲突。

scripts 里写什么命令才算真正生效
Composer 的 scripts 不是写完就自动跑的,它只在特定事件触发时执行,比如 composer install、composer update 或手动调用 composer run-script。你写的脚本不会在项目 require 一个包时悄悄运行,也不会在 PHP 启动时加载。
- 常见错误:把初始化逻辑(如生成配置文件)直接塞进
post-install-cmd,但 CI 环境常跳过install改用install --no-scripts,结果脚本完全不执行 - 推荐做法:对关键初始化动作,同时绑定
post-install-cmd和post-update-cmd,并确保文档里注明“首次部署需手动运行composer run-script init” - 注意路径上下文:脚本执行时工作目录是项目根目录,不是
vendor/bin,所以调用php bin/console没问题,但写./bin/console要确认文件可执行权限
如何让自定义 script 支持参数传递
Composer 原生不支持向 script 传参(比如 composer run-script build -- --env=prod),所谓“支持”其实是靠 shell 解析或工具链配合实现的。
- 最简方案:用
php -r包一层,例如"build": "php -r "\$env = getenv('SCRIPT_ENV') ?: 'dev'; echo "Building for \$env\n";"",然后通过SCRIPT_ENV=prod composer run-script build控制 - Laravel / Symfony 用户更常用:把逻辑移到 PHP 文件里,script 只负责调用,如
"build": "php scripts/build.php",参数由$argv或环境变量传入 - 坑点:Windows 下
%VAR%语法和 Unix 的$VAR不兼容,跨平台项目建议统一用getenv()+ 环境变量,别依赖 shell 层变量展开
post-autoload-dump 触发时机与性能陷阱
post-autoload-dump 在每次生成或更新 vendor/autoload.php 后执行,包括 install、update、甚至某些插件修改类映射时。它看似“轻量”,但容易引发隐式性能问题。
- 典型误用:在里面执行耗时操作,比如扫描整个
src/目录生成反射缓存——这会让composer update变慢数秒,开发者会下意识关掉所有 scripts - 正确姿势:只做必须与 autoloader 强耦合的事,比如生成 PSR-4 映射快照、清理旧的 classmap 缓存;其他构建任务应挪到独立 script 并明确调用时机
- 兼容性注意:该事件在 Composer 1.x 和 2.x 行为一致,但 2.2+ 开始支持
--no-autoloader,此时该钩子不会触发,你的清理逻辑可能漏掉
script 名称冲突与作用域隔离
Composer 不区分“全局 script”和“本地 script”,所有 scripts 都扁平注册。如果你依赖的包也定义了同名 script(比如都叫 test),它的定义会覆盖你项目的——而且没有警告。
- 现象:执行
composer test却跑起了 vendor 里某个测试框架的默认命令,而不是你写的phpunit --config phpunit.xml.dist - 解决办法:给自定义 script 加前缀,比如
"app:test"、"app:build",再用composer run-script app:test显式调用 - 额外好处:避免和 Composer 内置命令(
dump-autoload、clear-cache)重名,也方便 CI 脚本精准控制执行范围
真实项目里,script 的边界比想象中模糊:它既不是纯构建步骤,也不是部署钩子,更不是应用生命周期的一部分。最容易被忽略的是——它没有事务性,失败不会回滚前面的操作,出错时得靠人肉检查 vendor/ 状态。










