本地包替换必须用repositories + require,replace仅声明兼容性不执行文件操作;需先remove旧包,再在repositories中配置path类型仓库并require本地包,否则无法生效。

本地包替换必须用 repositories + require,不是改 replace
很多人误以为 replace 能让 Composer 自动把远程包换成你本地的代码——它不能。replace 只在依赖解析时“声明满足”,不触发任何文件操作,更不会把你的本地目录塞进去。真正实现本地包替换的唯一可靠路径是:repositories 声明本地路径,再用 require 明确拉取它。
常见错误现象:Your requirements could not be resolved,往往是因为旧包还在 require 里挂着,又加了 replace,Composer 直接懵了。
- 确保你要替换的包(比如
vendor/old-package)已从主项目的require中移除:运行composer remove vendor/old-package - 在主项目
composer.json的repositories数组里加一条type: "path"条目,url指向你本地包的绝对或相对路径(如"../my-forked-package") -
require字段里写上该包名和版本约束(如"vendor/old-package": "*"),版本号会被忽略,实际加载的是本地目录内容 - 执行
composer install或composer update vendor/old-package,Composer 默认创建符号链接(symlink),改本地代码立刻生效
path 仓库的 options 控制链接行为
默认 symlink 是开发友好型,但某些环境(如 Windows 某些 Docker 场景、CI 机器权限受限)可能无法创建符号链接,导致安装失败或加载不到类。这时得靠 options 显式控制。
- 加
"options": {"symlink": false}→ 强制复制文件到vendor,适合需要隔离变更或部署验证的场景 - 加
"options": {"drivers": ["git"]}→ 让 Composer 把本地目录当 Git 仓库读取(会尝试git rev-parse HEAD),可用于校验 commit hash - 不加
options时,Linux/macOS 默认 symlink,Windows 默认 copy(除非启用了开发者模式) - 注意:
options是repositories条目下的子字段,不是顶层配置
本地包的 composer.json 必须自洽
你本地那个被引用的包,不是“随便放个文件夹就行”。它的 composer.json 必须能独立通过 Composer 校验,否则主项目 install 会报错或静默跳过。
-
name字段必须和主项目require中写的完全一致(包括大小写、斜杠方向) -
autoload配置要正确,尤其是 PSR-4 映射路径需匹配实际src/结构,否则类根本加载不了 - 如果本地包依赖其他包(比如
php版本、扩展),这些require会参与主项目的依赖解析,可能引发冲突 - 建议本地包也跑一次
composer validate,提前暴露格式或逻辑问题
别忽略下游依赖还在拉旧包
即使你本地配好了 path,主项目也 clean 掉了旧包,只要某个已安装的依赖(比如 some-tool)仍在 require 旧包,composer install 就会在新机器或 CI 上重新把它拉回来——因为依赖图里它仍是刚需。
- 查谁在拖后腿:
composer depends vendor/old-package,输出非空就说明有“钉子户” - 解决方式只有两个:升级那个“钉子户”到支持新包的版本,或者 fork 它、改它的
composer.json中的require - 若上游长期不更新,
repositories+require仍是首选;此时replace可作为辅助,加在本地包的composer.json里防冲突,但别指望它起主要作用
本地包替换看着只是改几行 JSON,但实际生效链条很长:主项目删旧、声明仓库、本地包结构合规、下游无硬依赖、环境支持 symlink……漏掉任意一环,都可能表现为类找不到、方法不存在,或者干脆 composer install 卡死。











