Composer安装本地包需在主项目composer.json根级配置repositories,type为"path",url用相对路径,本地包含合法composer.json且name严格匹配require中的包名,版本写"dev-main"并设"minimum-stability": "dev"。

Composer 安装本地包不是“复制进去就完事”,而是必须让 Composer 把你的本地目录识别为一个合法包源,否则 vendor/ 里即使有文件,class_exists() 也会返回 false。
怎么配 repositories 才让 Composer 看得见本地包
配置必须写在项目根目录 composer.json 的顶层 repositories 字段里,不能嵌套、不能放错位置:
-
type必须是"path",写成"package"或漏掉会静默失效 -
url必须是相对于composer.json的路径,比如"./packages/my-utils";绝对路径(/home/xxx)、file://前缀、~/都不被接受 - 本地包目录下必须存在语法合法的
composer.json,且含"name"字段,值要和你在require中写的完全一致(大小写、连字符、斜杠全部敏感) - 本地包最好已运行
git init并至少有一个commit;否则 Composer 可能拒绝解析dev-main这类分支名,需手动加"version": "dev-main"绕过
require 时版本号怎么写才不会报 “Could not find package”
path 类型仓库不走语义化版本解析,只认明确的开发分支标识或显式 version 值:
- 写
"my-vendor/my-package": "dev-main"前提是本地包当前在main分支,且composer.json里有"version": "dev-main"或 Git HEAD 指向该分支 - 写
"my-vendor/my-package": "@dev"更稳妥,它强制走 path 源,不查 Packagist,也不依赖本地 Git 状态 - 千万别写
"*"、"^1.0"或空版本——这些会让 Composer 直接跳过 path 源,转头去 Packagist 找包,然后报错 - 如果项目没设
"minimum-stability": "dev",dev-main会被默认稳定性策略过滤掉,必须加这一行(推荐同时加"prefer-stable": true)
autoload 怎么配才能让 new MyPackageClass() 成功
主项目的 autoload 对本地包完全无效,必须靠本地包自己声明:
- 本地包的
composer.json里必须有"autoload"段,例如:"psr-4": {"MyPackage\": "src/"}(注意双反斜杠\和末尾斜杠) - 路径是相对于本地包根目录的,不是项目根目录;别写成
"src/MyPackage/"这种错误结构 - 改完本地包的 autoload 后,在主项目根目录执行
composer dump-autoload,否则新映射不会写入vendor/composer/autoload_psr4.php - 测试类在
tests/下?必须用"autoload-dev"单独声明,且末尾带反斜杠:"MyPackage\Tests\": "tests/",少一个就加载失败
改了本地包代码为什么 vendor 里没更新
默认情况下,path 仓库走的是复制(copy)模式,不是实时链接。改代码不生效,90% 是因为没启用 symlink:
- 在主项目
composer.json的对应repositories条目里加:"options": {"symlink": true} - Windows 用户需以管理员身份运行终端,或开启“开发者模式”,否则 symlink 会静默 fallback 到 copy
- 首次引入必须用
composer update my-vendor/my-package(不是install),因为install只读composer.lock,不重新解析仓库类型 - 验证是否真用了 symlink:
ls -la vendor/my-vendor/my-package(macOS/Linux)应显示->指向源目录;Windows 上用dir vendormy-vendormy-package看是否为“快捷方式”
最常被忽略的点:本地包的 composer.json 里 name 字段和主项目 require 中的包名必须逐字一致——差一个大写字母、多一个空格、斜杠方向不对,都会导致 Composer 静默跳过,然后报“Could not find package”。这不是网络问题,也不是缓存问题,是匹配失败。











