必须设 $alwaysNewInstance = true 或 make(..., true),因 Facade 默认单例以复用容器实例,避免状态残留;运行时改静态属性或重写 getFacadeClass() 等方式均无效。

直接设 $alwaysNewInstance = true,或者调用 make() 时传 $newInstance = true。这是唯一可靠的方式,其他“重写 getFacadeClass()”或“改容器绑定”都不起作用。
为什么默认是单例?
Facade 本质是代理容器实例,而容器(Container)默认复用已创建的对象。比如 Db::table() 多次调用,背后是同一个 think\db\Connection 实例在干活 —— 这能省开销,但也会导致状态残留(如上次查询的 where 条件没清掉)。
-
Container::make('db')第二次调用直接返回缓存的实例,除非显式传true -
Facade::__callStatic()内部调用的正是createFacade(),而它会检查static::$alwaysNewInstance - 所有系统内置 Facade 类(如
\think\facade\Db、\think\facade\Config)都继承自\think\Facade,共享该静态属性
两种生效的设置方式
必须选其一,且需在 Facade 类定义时就确定,运行时改 $alwaysNewInstance 无效(因为 createFacade() 是静态方法,读取的是类定义时的值)。
- 在自定义 Facade 类里加一行:
protected static $alwaysNewInstance = true; - 或不改类,改调用方式:用
\think\Facade::make('db', [], true)替代Db::table()—— 注意这不是 Facade 静态调用,而是直接走容器
示例(自定义 Facade):
立即学习“PHP免费学习笔记(深入)”;
namespace app\Facade;
use think\Facade;
class MyService extends Facade
{
protected static $alwaysNewInstance = true;
protected static function getFacadeClass()
{
return 'app\common\MyService';
}
}
常见踩坑点
很多人试过这些,但都无效:
- 在
getFacadeClass()里返回带时间戳的字符串(如'my_service_'.time())—— 容器找不到对应绑定,直接抛InvalidArgumentException - 在控制器里执行
Db::$alwaysNewInstance = true—— 属性是static,但 PHP 不允许运行时修改类的静态属性值 - 以为调用
Container::getInstance()->bind('db', ...)能覆盖行为 —— 绑定只影响“找哪个类”,不影响“是否复用实例” - 误用
instance()方法:它只是封装了make($args, false),不接受$newInstance参数
真正要每次新实例,就得从 $alwaysNewInstance 或 make(..., true) 入手。别绕弯,这两条路是源码里唯二触发 !$newInstance 分支的地方。



















