Facade本身不缓存实例,真正复用实例的是容器对绑定标识(如'cache')的singleton注册;每次Cache::get()实际调用Container::getInstance()->make('cache'),因首次创建后复用同一对象,故实例贯穿请求。

Facade 本身不缓存实例,是底层容器在 bind / singleton 时做了单例绑定
ThinkPHP 的 Cache、Db、Log 等 Facade 类本质是静态代理,它们通过 getFacadeAccessor() 返回一个容器绑定标识(如 'cache'),再由服务容器(Container)负责解析并返回实例。真正“被缓存”的,是容器对这个标识的解析结果。
- 每次调用
Cache::get(),实际走的是:Container::getInstance()->make('cache') - 而
'cache'这个键在容器中默认以singleton方式注册,即首次调用时 new 实例并保存,后续都复用同一对象 - 这个行为与 Laravel 的
Application::singleton()逻辑一致,不是 Facade 的特性,而是容器的设计选择
所以你看到“同一个 Cache 实例贯穿请求”,不是 Facade 记住了它,而是容器没重新造轮子。
为什么改了配置但 Cache 实例没更新?
因为容器在应用启动初期就完成了绑定,后续修改配置(比如 runtime/cache.php 被覆盖、或手动改了 config('cache.stores.redis.host'))并不会触发容器重 bind —— 它只认初始化时读到的值。
立即学习“PHP免费学习笔记(深入)”;
- 常见现象:
Cache::get()仍连旧 Redis 地址,即使 config 文件已改 - 根本原因:容器实例已创建,且驱动类(如
think\cache\driver\Redis)在构造时就固化了 host/port/password - 解决路径不是“刷新 Facade”,而是“重启容器上下文”:执行
php think clear:cache+php think cache:clear,再确保下次请求重建容器 - 开发中可临时用
$cache = \think\Cache::getInstance('redis', $newOptions)绕过容器直接新建驱动实例(适合调试)
如何验证当前 Cache 实例是否真的被复用?
最直接的办法是打日志或 dump 对象 ID:
dump(spl_object_id(Cache::store('file')));
dump(spl_object_id(Cache::store('file')));
// 两次输出相同数字 → 是同一个实例
注意:Cache::store('redis') 和 Cache::store('file') 返回不同实例,因为它们对应容器里不同的绑定键('cache.redis' vs 'cache.file')。
哪些操作会意外打破单例性?
看似无害的写法,实则绕过了容器管理,导致多次 new 实例:
- 手动 new 驱动类:
new \think\cache\driver\Redis($options)→ 每次都是新对象,不走容器,也不受配置中心控制 - 在中间件或控制器构造函数里提前调用
Cache::get()→ 此时容器可能尚未完成全部绑定,部分驱动未初始化,会 fallback 到默认驱动甚至报错 - 多级子应用共用同一个容器但未隔离缓存 store 名称 →
app1和app2都调Cache::store('redis'),拿到的其实是同一个实例,共享连接池
单例不是银弹。需要隔离场景(如多租户、灰度环境)时,别依赖默认 store,显式传 name 或 options 构建独立实例更可控。



















