Packagist识别包需满足四点:仓库公开、composer.json在根目录、name格式为vendor/package且vendor与Packagist用户名一致、autoload字段有效配置;否则提交必报“Package not found”。

composer.json 必须合法且位于公开仓库根目录,否则 Packagist 根本不会识别你的包。
Packagist 不托管代码,只索引公开 Git 仓库中 main(或 master)分支根目录下的 composer.json。你本地写得再规范,只要没满足这四点,提交后必然报 “Package not found”:
- 仓库设为 public(私有仓库直接被跳过)
-
composer.json文件存在且在根目录,不能放在dev/或package/子目录里 -
name字段格式为vendor/package,其中vendor必须与你在 Packagist 注册的用户名完全一致(大小写敏感) -
autoload字段必须存在,且至少含一个有效映射(如"psr-4": {"MyVendor\MyPkg\": "src/"})
常见错误现象:
- 提交 URL 后显示 “Invalid package name” → 检查 GitHub 用户名和
name中的 vendor 是否拼写、大小写都一致 - 页面提示 “Could not clone…” → 仓库是 private,或 GitHub token 权限不足(需勾选
public_repo) - 包页面显示 “No versions available” →
version字段被手动填了(应留空),或没打符合语义化版本的 tag(如v1.0.0,不是1.0.0或release-1.0)
git push origin v1.0.0 是触发自动更新的关键动作,不是 git push --tags。后者可能推送大量旧 tag,导致 Packagist 误判或延迟更新。
autoload 配置错误会导致安装成功但类找不到
哪怕 composer require yourname/your-pkg 成功执行,运行时仍可能报 Class not found —— 这几乎全是 autoload 配置问题。
典型错误包括:
- 命名空间末尾漏掉反斜杠:
"MyVendor\MyPkg"写成"MyVendor\MyPkg"(看起来一样?不,JSON 解析时若未转义双反斜杠,实际变成单反斜杠,PHP 命名空间解析失败) - 目录路径写错:
"src/"对应的是项目根目录下的src/,但如果实际代码在lib/下却没改配置,自动加载器就找不到类 - PSR-4 映射前缀与文件物理路径不匹配:比如声明
"MyVendor\MyPkg\": "src/",但src/Hello.php里写的是namespace App\Hello;,而非namespace MyVendor\MyPkg; - 混用 PSR-4 和 classmap:classmap 不会随文件增删自动更新,开发中建议全程用 PSR-4,发布前跑一次
composer dump-autoload -o确认映射正确
验证方式很简单:安装包后,打开 vendor/composer/autoload_psr4.php,搜你的 vendor 名,看映射路径是否指向你预期的目录,且命名空间字符串结尾有双反斜杠。
type 字段影响 Laravel/ThinkPHP 等框架的自动发现行为
虽然大多数纯库设 "type": "library" 就够用,但如果你做的是框架扩展(如 Laravel Package 或 ThinkPHP Extension),type 值必须匹配生态约定:
- Laravel 扩展应设为
"type": "laravel-package",否则php artisan vendor:publish不识别配置/迁移文件 - ThinkPHP 扩展推荐
"type": "thinkphp-extension",配合服务提供者才能被自动注册 - Yii2 扩展则需
"type": "yii2-extension",否则无法触发bootstrap流程
这个字段本身不影响 Composer 安装,但它决定框架能否“感知”到你的包。漏填或填错,会导致:
- 配置文件无法发布(
php artisan vendor:publish --provider="Your\Provider"找不到) - 服务提供者不被自动加载(即使写了
extra.laravel.dont-discover也没用) -
composer install时不触发框架特定的 post-autoload-dump 脚本
require 中的 PHP 版本约束过严会直接拦住 90% 的潜在用户
别写 "php": "^8.2.0",除非你真用了 PHP 8.2 特有语法(如 random_bytes() 的新签名)。更现实的做法是:
- 新项目起步可设
"php": ">=8.0.0" - 兼容老系统就拉到
"php": ">=7.4.0",但注意match表达式、属性 Promotion 等特性不可用 - 如果用了
str_contains()这类 8.0+ 函数,就别假装支持 7.4
另一个高频坑是框架版本锁死:
- 写
"topthink/framework": "^8.0"没问题,但若写成"^8.0.12"就会拒绝安装 8.0.13 —— 实际上 patch 版本应默认兼容 - Laravel 同理,
"illuminate/support": "^10.0"比"10.42.0"更合理
最麻烦的是隐式依赖冲突:你声明支持 "guzzlehttp/guzzle": "^7.0",但用户项目已用 "^8.0",Composer 就会直接拒绝安装,而不是降级——此时要么放宽约束,要么用 conflict 明确声明不兼容项。
Packagist 自动同步依赖 tag 推送,不是 commit 更新
很多人以为 push 一次 main 分支就能让 Packagist 刷新,其实不会。它只在两种情况下抓取新内容:
- 你打了新 tag 并
git push origin v1.0.1 - 你手动进 Packagist 包页点 “Update”(仅限你有维护权限)
而且 Packagist 不解析分支历史,只看 tag 名是否符合语义化版本(v[0-9]+.[0-9]+.[0-9]+ 或 [0-9]+.[0-9]+.[0-9]+),带预发布标识(如 v1.0.0-beta.1)也能识别,但 rc1、alpha 等后缀需确保格式标准。
容易被忽略的一点:tag 必须推送到远端,且对应 commit 必须包含当时有效的 composer.json(name、autoload 等字段不能缺失)。如果 tag 指向一个还没加 autoload 的旧 commit,那这个版本在 Packagist 上就是“安装成功但无法 autoload”的残缺状态——调试起来极难定位。











