
scripts 里写的命令到底怎么被触发
Composer 的 scripts 不是写完就自动运行的,它只是注册了一组命名任务,必须显式调用才能执行。比如你写了 "post-install-cmd": "php build.php",那只有在 composer install 结束后才跑;如果想手动跑,得用 composer run-script post-install-cmd 或更短的 composer run post-install-cmd。
常见错误现象:composer install 没反应、脚本文件没执行、报错 Script not found——基本都是路径不对或没加可执行权限,或者根本没触发对的钩子。
- 钩子名(如
pre-autoload-dump)有固定列表,不能随便起名;自定义脚本名可以任意,但要用composer run xxx显式调用 - 脚本内容支持四种格式:shell 命令字符串、PHP 回调数组
["MyClass", "myMethod"]、闭包(仅 CLI 环境)、外部脚本路径(需可执行或带解释器,如php ./build.php) - PHP 回调方式下,类必须能被 Composer 自动加载到,否则报
Class not found
怎么让 PHP 脚本在 scripts 里安全执行
直接写 "build": "php build.php" 看似简单,但容易出问题:当前工作目录不一定是项目根目录,build.php 可能找不到依赖或配置文件;另外,PHP 脚本 exit 非 0 时,Composer 默认会中断后续流程(比如你只想 warn 不想 fail)。
使用场景:生成版本号、清理缓存、检查代码规范、打包前端资源等需要稳定上下文的操作。
- 统一用
php ${PWD}/build.php或php ./build.php,避免相对路径歧义;推荐用./开头,Composer 会以composer.json所在目录为基准解析 - 加
--no-interaction和--quiet参数控制输出,防止交互卡住 CI 流程 - 若允许失败继续,加
|| true(shell)或在 PHP 脚本里显式exit(0),但注意这会掩盖真实错误 - 别在脚本里改
vendor/或composer.lock,可能破坏依赖一致性
scripts 参数传值和环境变量怎么用
Composer 本身不支持像 npm 那样用 npm run build -- --env=prod 传参,scripts 字段里的命令是静态字符串,参数要靠环境变量或外部封装。
性能 / 兼容性影响:过度依赖环境变量会让本地调试和 CI 配置割裂;而硬编码又缺乏灵活性。
- 推荐方式:用 shell 包装一层,比如
"build": "sh -c 'php build.php \"$1\"' _ --env=prod",其中_占位符让$1指向第一个实际参数 - 环境变量优先走
$_ENV或getenv(),不要依赖$_SERVER,CLI 下不一定存在 - CI 场景下,GitLab CI/ GitHub Actions 可直接注入
COMPOSER_ENV=staging,PHP 脚本里读取即可 - 注意 Windows cmd 对引号和变量语法的支持差异,跨平台脚本建议统一用 PowerShell 或只走 PHP 层解析
为什么 post-update-cmd 有时不执行
这个钩子只在 composer update 成功完成、且 composer.lock 实际被修改时才触发。如果依赖没变、或用了 --dry-run、或更新中途失败,它都不会跑。
容易踩的坑:把它当成“每次 update 都该做的事”来用,结果在 CI 上漏掉关键步骤,比如没重新生成 autoload、没刷新缓存。
- 检查是否真有 lock 文件变更:对比前后
git status composer.lock - 确认没有加
--no-scripts参数(某些 CI 模板默认加了) - 如果想确保某操作总被执行,别依赖钩子,改用
composer run deploy这类显式命令,在 CI 脚本里单独调用 - 钩子函数内抛异常会导致整个 update 失败,日志只显示
Script ... returned with error code 255,建议在 PHP 脚本里捕获异常并明确echo错误信息
复杂点在于:钩子执行时机、工作目录、错误传播逻辑都不是完全透明的,尤其混合使用 PHP 回调和 shell 命令时,调试得靠 composer run xxx -v 看详细输出,而不是猜。










