Laravel单例模式失效:为何两次请求生成两个实例?
Laravel 单例未生效的原因与解决方案
问题分析
你遇到的情况是正常现象:Laravel 框架中的 singleton 绑定是单请求生命周期内的单例。每个 HTTP 请求会启动一个独立的 PHP 进程,进程之间内存完全隔离,所以两次 curl 请求属于两个不同的进程,自然会各自创建 SingleTest 实例,触发两次构造函数日志。
代码验证
你的现有代码本身是正确的,在同一个请求内多次获取实例只会初始化一次。比如修改路由为:
Route::get('/test-same-request', function () { $instance1 = app(SingleTest::class); $instance2 = app(SingleTest::class); // 输出 true,说明同一请求内是同一个实例 return var_dump($instance1 === $instance2); });
访问这个路由,日志只会出现一次 init instance,符合单例预期。
实现跨请求的"全局单例"
如果需要实现跨多个请求的真正全局单例(跨进程共享实例),需要借助外部存储来持久化实例状态,比如 Redis:
- 修改服务类,支持序列化与反序列化:
<?php namespace App\Services; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Redis; class SingleTest { public string $var; public function __construct(string $var) { $this->var = $var; Log::info('init instance'); } // 从Redis获取或创建实例 public static function getInstance(): self { $key = 'singleton:SingleTest'; $data = Redis::get($key); if ($data) { return unserialize($data); } $instance = new self('test singleton'); Redis::set($key, serialize($instance)); // 设置过期时间(可选) Redis::expire($key, 3600); return $instance; } }
- 修改路由调用方式:
Route::get('/test1', fn() => SingleTest::getInstance()->var); Route::get('/test2', fn() => SingleTest::getInstance()->var);
此时两次 curl 请求只会触发一次构造函数日志,实现跨请求的单例效果。
注意:序列化对象时要确保类的属性都是可序列化的,避免出现序列化失败的情况。
内容的提问来源于stack exchange,提问作者vbulash
相关产品推荐
相关产品推荐

