You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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:

  1. 修改服务类,支持序列化与反序列化:
<?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;
    }
}
  1. 修改路由调用方式:
Route::get('/test1', fn() => SingleTest::getInstance()->var);
Route::get('/test2', fn() => SingleTest::getInstance()->var);

此时两次 curl 请求只会触发一次构造函数日志,实现跨请求的单例效果。

注意:序列化对象时要确保类的属性都是可序列化的,避免出现序列化失败的情况。

内容的提问来源于stack exchange,提问作者vbulash

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 12:24:55