前情提要
-
由于 FileStore 在存储不过期的key的expire时使用了
9999999999
, 导致最后在使用 Carbon 处理时日期溢出, 因此自己修改了一下, 新增一个App\Extensions\Cache\FileStore
文件<?php namespace App\Extensions\Cache; class FileStore extends \Illuminate\Cache\FileStore { protected function expiration($seconds) { $expiration = parent::expiration($seconds); return $expiration === 9999999999 ? 2147483600 : $expiration; } }
-
并在
App\Providers\AppServiceProvider::boot()
中扩展该缓存驱动Cache::extend('file2', function ($app, $config) { return Cache::repository(new FileStore($app['files'], $config['path'])); });
-
最后修改了默认的缓存驱动
config/cache.php
return [ 'default' => 'file2', 'stores' => [ ... 'file' => [ 'driver' => 'file2', ... ], ... ] ];
这时候问题出来了, 无论是启动 php artisan tinker
或网页直接访问, 都会报错:
Driver [file2] is not supported
先一顿分析
- laravel/telescope 在 composer.json 中配置了包自动发现策略:
extra.laravel.providers: ["Laravel\\Telescope\\TelescopeServiceProvider"]
composer 在安装/更新包时, 会将所有安装的包的信息存储在
vendor/composer/installed.json
, 其中包含每个包的安装信息及其配置的composer.json文件 -
项目 composer.json 根据其配置
`scripts.post-autoload-dump
在autoload-dump
后会执行php artisan package:discover --ansi
命令上述命令对应的是
Illuminate\Foundation\Console\PackageDiscoverCommand
文件.它会调用
Illuminate\Foundation\PackageManifest::build()
, 该方法会将vendor/composer/installed.json
中配置了extra.laravel.providers
的项提取出来, 并保存在bootstrap/cache/packages.php
中.这部分解析可以参考: https://divinglaravel.com/lar...
-
在laravel启动过程中,
Illuminate\Foundation\Application::registerConfiguredProviders()
会逐个注册所需的服务提供者, 服务提供者列表来源包括:config('app.providers')
以及 laravel 包自动发现策略.public function registerConfiguredProviders() { $providers = Collection::make($this->config['app.providers']) ->partition(function ($provider) { return Str::startsWith($provider, 'Illuminate\\'); }); $providers->splice(1, 0, [$this->make(PackageManifest::class)->providers()]); (new ProviderRepository($this, new Filesystem, $this->getCachedServicesPath())) ->load($providers->collapse()->toArray()); }
上述代码分析:
第3行: 将配置中
app.providers
中的服务提供者根据字符串前缀匹配分开, 此时$providers
值大致是这样的:{ 0 : [ "Illuminate\....." ... "Illuminate\....." ], 1 : [ "App\Providers\AppServiceProvider::class", ... "App\Providers\RouteServiceProvider::class", ], }
第8行: 将laravel包自动发现策略获取的服务提供者列表插入到
$providers
数组中1
的位置, 原先的1
挪到2
, 此时$providers
数组大致如下:{ 0 : [ "Illuminate\....." ... "Illuminate\....." ], 1 : [ ... "Laravel\Telescope\TelescopeServiceProvider", ... ], 2 : [ "App\Providers\AppServiceProvider", ... "App\Providers\RouteServiceProvider", ], }
第10行: 将
$providers
数组扁平化, 顺序则是依次 0, 1, 2 这样分别 register(注册) 这些服务提供者.
-
在laravel启动初始化的最后还会依次按 register(注册) 的顺序依次 boot(启动)上述注册的服务提供者.
对于
Laravel\Telescope\TelescopeServiceProvider
这个服务提供者, 按照如下的调用顺序Laravel\Telescope\TelescopeServiceProvider::boot() | V Laravel\Telescope\Telescope::start() | V Laravel\TelescopeRegistersWatchers::registerWatchers() | V Laravel\Telescope\Watchers\DumpWatcher::register() ↑ 这里的代码调用 $this->cache->get("...")
在
Laravel\Telescope\Watchers\DumpWatcher::register()
其中的代码调用了缓存相关接口, 然而此时根本就没有执行到App\Providers\AppServiceProvider::boot()
, 自然会导致报错无法找到该缓存驱动.
解决办法
基本思路就是调整 Laravel\Telescope\TelescopeServiceProvider
服务提供者的加载顺序, 使其在 App\Providers\AppServiceProvider
之后加载.
这里给出一个方案:
-
配置项目的
composer.json
, 使laravel的包自动发现策略忽略TelescopeServiceProvider
{ ... "extra": { "laravel": { "dont-discover": [ "laravel/telescope" ] } }, ... }
-
将
TelescopeServiceProvider
手动加入到服务提供者列表中, 注意顺序修改
config/app.php
return [ ... 'providers' => [ ... App\Providers\AppServiceProvider::class, ... Laravel\Telescope\TelescopeServiceProvider::class, App\Providers\TelescopeServiceProvider::class, ... ], ... ];
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。