最可靠方法是用 app($abstract) 两次并用 === 比较引用:若相等则是单例,否则非单例;还可查服务提供者中 singleton() 绑定或 inspect $instances 数组验证。

在 Laravel 6 中,判断一个对象是否被注册为单例(singleton),不能靠“看代码有没有写 singleton()”,而要通过容器的实际行为验证——因为绑定方式决定解析结果,而非命名或直觉。最可靠的方式是用两次 app() 获取并比较引用。
用 === 比较两次解析结果
这是最直接、无需调试器的方法:同一请求内,对同一个抽象调用两次 app($abstract),若返回的实例完全相等(===),说明它是单例;否则就是每次新建。
-
单例表现:
app(Cache::class) === app(Cache::class)返回true -
非单例表现:
app(Request::class) === app(Request::class)返回false(Request 是 bind 绑定的,每次新建)
检查绑定类型:查服务提供者的 register() 方法
单例必须在服务提供者(如 AppServiceProvider)的 register() 方法中注册。打开对应文件,搜索 singleton( 或 bind(:
- 出现
$this->app->singleton(...)→ 是单例绑定 - 出现
$this->app->bind(...)且无第三个参数true→ 默认不是单例 - 注意:
$this->app->singleton(...)等价于$this->app->bind(..., ..., true)
查看容器内部缓存数组(调试时)
容器内部用 $instances 数组缓存已解析的单例实例。可在调试中访问(仅限开发环境):
-
dd(app()->getInstances())→ 显示当前已缓存的所有单例实例(键为抽象名,值为对象) - 空数组不等于没单例,因为有些单例可能尚未被首次解析(
make()还没调用过) - 若某个类名出现在该数组中,说明它已被解析且是单例
避免误判的常见陷阱
有些情况看起来像单例,实则不是:
-
app()本身是单例,但不等于它管理的所有服务都是单例 -
instance()绑定的是已存在对象,它会被复用,但它绕过依赖注入,不属于“容器管理的单例” - 在 Swoole 或 Octane 环境下,单例可能跨请求存活,此时
===在不同请求间也成立——但这属于运行环境异常,不是 Laravel 设计本意











