该用 composer install;它读取 composer.lock 安装锁定版本,确保环境一致,仅在需升级依赖时才用 composer update 并建议指定包名。

composer install 和 composer update 到底该用哪个?
composer install 读 composer.lock,只装锁定版本;composer update 忽略 lock 文件,重新解析依赖树、升级到符合约束的最新版本。
- 新项目首次部署或 CI 构建时,必须用
composer install—— 否则可能装出和开发环境不一致的包版本 - 只有明确要升级依赖(比如修安全漏洞、用新特性)才运行
composer update,且建议加具体包名:composer update monolog/monolog,避免连带升级一堆无关包 -
composer update在团队协作中容易引发意外:比如某人本地跑了一次,提交了新composer.lock,其他人git pull后再composer install就会装上不同版本 —— 这不是 bug,是 lock 文件本意,但常被忽略
多个项目共用同一套 vendor 怎么办?
不能。Composer 没有“全局 vendor 目录”机制,每个项目必须有独立的 vendor/ 目录。
- 全局安装(
composer global require)只影响~/.composer/vendor/和~/.composer/vendor/bin/,这些二进制命令(如phpunit、larastan)可被 shell 找到,但不会被任何项目的 autoloader 加载 - 试图 symlink 多个项目共享一个
vendor会导致 autoload 冲突、类加载失败、composer dump-autoload失效 - 真正节省磁盘空间的方法是启用 Composer 的
cache-dir(默认已开),它复用下载的 zip 包和解压缓存,而不是复用vendor
为什么 vendor/autoload.php 不能跨项目 require?
因为每个项目的 vendor/autoload.php 是根据自身 composer.json 生成的,只认识自己声明的命名空间和路径。
- 假设项目 A 声明了
"psr-4": {"App": "src/"},项目 B 声明了"psr-4": {"MyApp": "app/"},它们的 autoloader 注册规则完全不同 - 如果在项目 B 中
require '../project-a/vendor/autoload.php',那项目 A 的App类会被加载,但项目 B 自己的类可能反而找不到 —— autoloader 顺序错乱,class_exists()行为不可控 - 正确做法:把可复用的逻辑抽成独立包,发布到私有仓库或 Packagist,然后各项目通过
composer require引入,由 Composer 统一管理加载
全局命令和局部命令冲突时谁生效?
Shell 查找命令时只看 $PATH,跟 Composer 无关;但执行时是否走全局安装的二进制,取决于 $PATH 中哪个目录排更前。
-
composer global bin显示全局 bin 目录(通常是~/.composer/vendor/bin) - 你执行
phpunit时,系统从$PATH左到右找第一个匹配的phpunit文件 - 如果项目里也通过
composer require --dev phpunit/phpunit装了,它的vendor/bin/phpunit就在当前目录下,但除非你显式写成./vendor/bin/phpunit或把./vendor/bin加进$PATH,否则不会优先使用它 - 容易踩的坑:CI 脚本里直接写
phpunit,结果跑的是全局旧版本,而本地开发用的是项目内新版 —— 应统一用./vendor/bin/phpunit
路径和加载机制比表面看起来更刚性,改错一处就可能让类找不到、命令行为漂移、lock 文件失效——不是配置问题,是 Composer 的设计前提就拒绝模糊边界。