只有满足全部条件时才应封装为独立Composer包:被3+项目复用且不共享仓库、需语义化版本控制、有明确对外API与文档、具备长期维护能力;否则优先使用Service Provider+目录组织+composer dump-autoload。

直接封装成 Composer 包是可行的,但绝大多数 Laravel 项目根本不需要走这一步——90% 的“自定义封装需求”用服务提供者(Service Provider)+ 目录结构组织 + composer dump-autoload 就够了。
什么时候该封装成独立 Composer 包?
只有满足以下全部条件时才值得单独发包:
- 组件要被 3 个及以上不同 Laravel 项目复用,且这些项目不共享代码仓库
- 需要语义化版本控制(如
v1.2.0),并支持composer update vendor/package独立升级 - 有明确的对外契约:公开 API、文档、测试用例、PHP/Laravel 版本兼容声明
- 团队具备维护包的长期投入能力(包括安全更新、BC break 处理)
否则,强行发包只会增加发布流程、版本同步、依赖冲突等额外负担。
更实用的封装路径:从服务提供者开始
在当前项目中封装可复用逻辑,优先走 Laravel 原生支持的服务提供者机制:
- 运行
php artisan make:provider CustomPackageServiceProvider - 在
register()中绑定接口与实现,例如:$this->app->singleton('custom.logger', function () { return new CustomLogger(); }); - 在
boot()中加载视图、发布配置、注册路由或事件监听器 - 把核心类放在
app/CustomPackage/下,按功能分目录(Contracts/、Services/、Exceptions/) - 执行
composer dump-autoload -o让新命名空间生效
这种方式无需发布到 Packagist,也能获得自动加载、依赖注入、配置发布等完整 Laravel 生态支持。
如果真要发 Composer 包,必须处理的 3 个关键点
跳过这些,包要么装不上,要么运行时报错:
-
composer.json中必须声明"autoload": {"psr-4": {"Vendor\Package\": "src/"}},且命名空间前缀和目录严格对应 - 必须在
src/Providers/PackageServiceProvider.php中继承IlluminateSupportServiceProvider,并在composer.json的extra.laravel.dont-discover之外显式注册(或通过extra.laravel.providers自动发现) - 所有对 Laravel Facade 的调用(如
DB::、Cache::)必须确保包的require列表包含"illuminate/support"及对应子包,不能只写"laravel/framework"—— 否则低版本 Laravel 会因找不到具体类而崩溃
别忽略 config 和 migration 的发布机制
用户安装你的包后,得能一键发布配置和迁移文件:
- 在服务提供者
boot()中调用$this->publishes([__DIR__.'/../config/custom.php' => config_path('custom.php')], 'custom-config') - 用
php artisan vendor:publish --tag=custom-config触发 - 迁移文件必须放在
src/database/migrations/并在boot()中用$this->loadMigrationsFrom(__DIR__.'/../database/migrations');注册 - 切勿在包里直接执行
php artisan migrate—— 这属于用户项目职责
真正难的不是写代码,而是让包在别人的 Laravel 版本、PHP 版本、Autoload 配置下稳定工作。多数人卡在 autoload 映射错误或服务提供者未被发现,而不是逻辑本身。


















