
本文详解如何在 Laravel 9 中安全、规范地注册并使用 Yasumi 节假日库,解决因 Laravel 容器绑定方式变更导致的 Argument #2 must be of type Closure|string|null 错误,并提供可复用的服务提供者配置与最佳实践。
本文详解如何在 laravel 9 中安全、规范地注册并使用 yasumi 节假日库,解决因 laravel 容器绑定方式变更导致的 `argument #2 must be of type closure|string|null` 错误,并提供可复用的服务提供者配置与最佳实践。
在 Laravel 9 中集成 Yasumi(一个功能完备的 PHP 节假日计算库)时,直接沿用旧版 Laravel(如 5.x)中基于字符串或对象实例的容器绑定方式将引发运行时错误:
Illuminate\Container\Container::bind(): Argument #2 ($concrete) must be of type Closure|string|null
该错误的根本原因在于:Laravel 9 的服务容器 singleton() 方法严格要求第二个参数必须是 Closure(匿名函数)、string(类名或别名)或 null,而原代码中传入的是 Yasumi\Yasumi::create(...) 的执行结果(即一个 Yasumi 实例),属于对象类型,违反了类型约束。
✅ 正确做法是:将创建逻辑封装为闭包(Closure),交由容器在首次解析时延迟执行,确保线程安全、年份动态、依赖注入兼容。
✅ 推荐实现方式(AppServiceProvider)
在 app/Providers/AppServiceProvider.php 的 register() 方法中,按如下方式注册:
use Illuminate\Support\ServiceProvider;
use Carbon\Carbon;
use Yasumi\Yasumi;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
// ✅ 正确:传入 Closure,支持延迟初始化与动态年份
$this->app->singleton('yasumi', function ($app) {
$year = Carbon::now()->year; // 动态获取当前年份(也可从配置/请求上下文注入)
return Yasumi::create('USA', $year); // 支持任意 ISO 国家码,如 'JP', 'DE', 'GB'
});
// ✅ 进阶:同时绑定接口契约(推荐用于解耦与测试)
$this->app->singleton(\Yasumi\Yasumi::class, function ($app) {
return $app->make('yasumi');
});
}
public function boot()
{
// 可选:全局辅助函数或 Facade 注册(见下文)
}
}? 使用示例
在控制器或服务中,可通过依赖注入或容器解析获取实例:
// 方式 1:依赖注入(推荐)
use Yasumi\Yasumi;
class HolidayController extends Controller
{
public function index(Yasumi $yasumi)
{
$holidays = $yasumi->getHolidays(); // 返回 CarbonPeriod 或数组(取决于版本)
return response()->json($holidays->map->toArray());
}
}
// 方式 2:容器解析(适用于非构造器场景)
$yasumi = app('yasumi');
$easter = $yasumi->getHoliday('easter');⚠️ 注意事项与最佳实践
- 避免硬编码年份:Yasumi::create() 的第二参数应为具体年份(int),不可传入 Carbon 实例。建议通过 Carbon::now()->year 或配置项(如 config('app.holiday_year'))管理。
- 国家代码标准化:使用 ISO 3166-1 alpha-2 标准代码(如 'CN', 'FR'),Yasumi 内置支持 100+ 国家/地区。
- 性能考虑:Yasumi::create() 是轻量级操作,但若高频调用,可结合 Laravel 缓存(如 Cache::remember())缓存节假日列表。
- 扩展性建议:可封装为自定义 Facade 或专用 Service 类(如 HolidayService),隐藏 Yasumi 底层细节,便于单元测试与多国切换。
✅ 验证是否生效
运行以下 Artisan 命令检查绑定是否成功:
php artisan tinker
>>> app('yasumi')->getHoliday('newYearsDay')->format('Y-m-d')
=> "2024-01-01"至此,Yasumi 已在 Laravel 9 中完成合规集成,既符合框架容器规范,又保留了节假日计算的灵活性与准确性。










