当前位置:首页>php>PHP 中 static::class 与 self::class 的差别远比想象中重要

PHP 中 static::class 与 self::class 的差别远比想象中重要

  • 2026-07-02 16:33:45
PHP 中 static::class 与 self::class 的差别远比想象中重要

很多 PHP 开发者在写下这两段代码时并不会多想:



1
2
3
4
5
6
7
8
9
10
11

class Repository{
    publicfunction modelClass(): string{
        return self::class;
    }
}

class Repository{
    publicfunction modelClass(): string{
        return static::class;
    }
}


在同一份文件、独立运行时,它们返回的字符串完全一致,都是 "Repository"。测试通过,代码评审放行,大家继续往下推进。

直到有人给 Repository 加上了子类,比如 UserRepository extends Repository。此时第一种写法仍旧返回 "Repository",第二种则会返回 "UserRepository"。根据用到这个值的场景,这段代码要么是一个完全通用的基类,要么就是一个只在子类存在时才会暴露的 bug——而子类真正存在的地方往往是生产环境。

本文会深入探讨 PHP 中 static 与 self 的差别。重点不是语法,而是语义:何时该用哪个、选错时会出什么问题,以及这个选择会在哪些模式里被放大——工厂方法、仓储基类、事件类、Eloquent scope、带 clone with 语义的 DTO 等等。两个关键字之间的差别很小,引发的 bug 却一点都不小。

TL;DR 速览

  • • self:: 指向代码所在的类,在解析/编译期就被锁定。
  • • static:: 指向实际被调用的类,在运行时通过后期静态绑定(LSB)解析。
  • • 在基类方法中,self::class 返回基类名;static::class 在子类调用时返回子类名。
  • • 选错不会报错,只会悄悄返回错误的类、错误的实例、或者错误的常量——而这种 bug 只会在有人继承代码时显现。
  • • 经验法则:如果写的是需要被继承的代码,默认使用 static::,除非确实想把行为锁定在当前类。
  • • self::classstatic::class 以及对象上的 ::class(PHP 8+ 的 $obj::class)各自有独立的语义,混用就是隐蔽 bug 的温床。

本文要点

  • • 后期静态绑定的精确机理——写下 static:: 时 PHP 在运行时究竟做了什么
  • • 真正会改变行为的六个场景(不只是类名,还有常量、方法、属性、new、类型提示、克隆)
  • • 决定程序正确性的现实模式:工厂、仓储、事件、DTO、流式构建器
  • • PHP 8+ 新增特性($object::classnew static(...)、克隆语义)与 LSB 的联动
  • • 性能影响——确实存在,但几乎都不是关键
  • • 一套决策框架:何时选用哪个关键字,以及 self:: 客观更合适的唯一场景

真正能记住的思维模型

先把关键字本身放一边,想一想它们各自在回答什么问题。

self:: 回答的是:"我写在哪个类里?" 答案在 PHP 解析文件的那一刻就固定下来,永远不变。

static:: 回答的是:"最外层的 new 或方法调用是在哪个类上发起的?" 答案取决于运行时上下文,每次调用都可能不同。

当写下 class Foo 并在其中放一个方法时,这个方法属于 Foo。方法体内的 self:: 永远指向 Foo。即便有人写 class Bar extends Foo 并在 Bar 实例上调用这个方法,方法的定义仍在 Foo,所以 self:: 依旧解析为 Foo

static:: 的行为完全不同。PHP 会记录调用是从哪个类发起的。调用 Bar::theMethod() 时,PHP 会沿继承链向上找到 Foo 里的实现,但它记得这次调用源自 Bar。于是方法内部的 static:: 解析为 Bar

这就是"后期静态绑定"。"后期"是指解析发生得很晚——在调用时才确定,而不是解析时;"静态"是指它作用于静态式的类引用。

用代码来演示:



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

class Animal{
    publicfunction whoAmI(): void{
        echo "self::class    = " . self::class . "\n";
        echo "static::class  = " . static::class . "\n";
    }
}

class Dog extends Animal{}

(new Animal)->whoAmI();
// self::class    = Animal
// static::class  = Animal

(new Dog)->whoAmI();
// self::class    = Animal       ← 写在 Animal 中,永远锁定 Animal
// static::class  = Dog          ← 从 Dog 调起,解析为 Dog


全部秘密就是这一段。本文后面讲的所有场景,都是这一机制的自然推论。

会咬人的六个真实场景

两个关键字的差异只会在继承关系中才有意义。下面是六个会真正改变程序行为的场景,按从常见到微妙排序。

1. new self 与 new static——工厂方法的经典陷阱

这是最经典的一例。基类里有一个静态工厂方法:



1
2
3
4
5
6
7
8
9
10
11
12
13

class Model{
    public staticfunction make(array $data): Model{
        return new self($data);     // ← 永远创建 Model,无法创建子类
    }

    publicfunction __construct(protected array $data{}
}

class User extends Model{}

$user = User::make(['name' => 'Alice']);
var_dump($user instanceof User);    // false!
var_dump($user instanceof Model);   // true


new self() 把被实例化的类硬编码为 Model。哪怕调用方写的是 User::make(...),拿到的仍是 Model。这种结果几乎从来不是想要的。

修复方式是改成 new static



1
2
3
4
5
6
7
8
9
10
11
12
13

class Model{
    public staticfunction make(array $data): static{
        return new static($data);   // ← 按调用方所在的类实例化
    }

    publicfunction __construct(protected array $data{}
}

class User extends Model{}

$user = User::make(['name' => 'Alice']);
var_dump($user instanceof User);    // true
var_dump($user instanceof Model);   // true


同时返回类型也从 Model 改为 static。PHP 提供了一个特殊的 static 返回类型,含义是"返回值是实际被调用的那个类"。如果保留 Model,PHPStan、Psalm 这类静态分析器会抱怨 make() 声称返回 Model,实际上返回的是子类。改为 : static 之后,工具与读者就都理解了这层语义。

在真实项目里,这决定了一个作为基类的 Repository 到底是能适配所有实体,还是会静默地返回无用的 Repository 实例。Laravel 的 Model::create() 能够多态地工作,答案就在这里——Eloquent 的工厂方法内部都使用 static

2. 常量(self::CONST 与 static::CONST

PHP 5.3 为方法引入了后期静态绑定,常量则是后来跟进的,但遵循同样的规则:self:: 锁定,static:: 延迟解析。



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

class Config{
    const PREFIX = 'default';

    publicfunction fullKey(string $key): string{
        return self::PREFIX . ':' . $key;       // 永远是 'default:...'
    }

    publicfunction fullKeyDynamic(string $key): string{
        return static::PREFIX . ':' . $key;     // 若子类重新声明了常量,则使用子类的值
    }
}

class RedisConfig extends Config{
    const PREFIX = 'redis';
}

$c = new RedisConfig();
echo $c->fullKey('user');         // "default:user"       ← 出乎意料
echo $c->fullKeyDynamic('user');  // "redis:user"         ← 符合预期


这一类问题格外隐蔽,因为常量给人的直觉是"天然就应该多态"。事实并非如此。self:: 引用的常量在解析期就冻结为代码所在类的值。

当希望基类定义默认常量、允许子类覆盖时,必须使用 static::



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

class Event{
    const VERSION = 1;

    publicfunction toArray(): array{
        return [
            'type'    => static::class,
            'version' => static::VERSION,       // 子类可覆盖
            'at'      => (new DateTimeImmutable)->format(DATE_ATOM),
        ];
    }
}

class UserCreatedEvent extends Event{
    const VERSION = 3;    // 该子类的事件版本已经演进到 v3
}


如果写成 self::VERSION,无论子类怎么声明,所有子类事件都会上报 v1。安静、令人困惑,属于那种半年后调查事件 schema 不一致时才会被发现的 bug。

3. 可被覆盖的静态方法

同样的原则也适用于静态方法之间的互相调用:



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

class Query{
    public staticfunction tableName(): string{
        return 'default';
    }

    public staticfunction all(): array{
        $table = self::tableName();      // ← 硬绑定到 Query::tableName()
        return DB::select("SELECT * FROM $table");
    }
}

class Users extends Query{
    public staticfunction tableName(): string{
        return 'users';
    }
}

Users::all();   // SELECT * FROM default——并非期望结果


self::tableName() 根本不关心调用方其实是 Users::all()。因为它写在 Query 里,self:: 就意味着 Query,于是调用的是 Query::tableName()。子类的覆盖被完全绕过。

改为 static::



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

class Query{
    public staticfunction tableName(): string{
        return 'default';
    }

    public staticfunction all(): array{
        $table = static::tableName();    // ← 存在子类覆盖时优先使用
        return DB::select("SELECT * FROM $table");
    }
}

class Users extends Query{
    public staticfunction tableName(): string{
        return 'users';
    }
}

Users::all();   // SELECT * FROM users——符合预期


Laravel 的查询构建器与 Eloquent scope 的内部实现正是这种形态。基类搭建了一个由 static:: 构成的脚手架,子类按需填入自己的值。

4. instanceof 与类型检查

一个不太显眼的细节:在方法内部,instanceof self 和 instanceof static 含义不同。



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

class Animal{
    publicfunction isSameType(object $other): bool{
        return $other instanceof self;      // 任何 Animal 或其子类均为 true
    }

    publicfunction isExactType(object $other): bool{
        return $other instanceof static;    // 仅当具体类相同才为 true
    }
}

class Dog extends Animal{}
class Cat extends Animal{}

$dog = new Dog();
$anotherDog = new Dog();
$cat = new Cat();

$dog->isSameType($cat);         // true——都属于 Animal
$dog->isExactType($cat);        // false——Cat 不是 Dog
$dog->isSameType($anotherDog);  // true
$dog->isExactType($anotherDog); // true


instanceof self 的语义是"它是否与声明类同属一个继承层次";instanceof static 的语义是"它是否恰好是被调用的那个具体类"。

对一类需要拒绝跨类型比较的 DTO 相等性判断,通常想要 static——前提是可以接受"子类视为不同类型"。若要实现子类也算匹配的多态相等判断,则应使用 self(或 instanceof self)。

5. 带修改的克隆(clone 与 static

PHP 8.5 引入了 clone($object, [...]) 语法(以及此前常见的"手动 clone + 覆盖"写法),它们与 static 的组合值得特别理解。

DTO 里常见的模式:



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

abstractclass DTO{
    publicfunction with(array $changes): static
    {
        $clone = clone $this;
        foreach ($changes as $key => $value) {
            $clone->$key = $value;
        }
        return $clone;
    }
}

finalclass UserDTO extends DTO{
    publicfunction __construct(
        public string $name,
        public string $email,
    ) {}
}

$u  = new UserDTO('Alice', 'alice@example.com');
$u2 = $u->with(['name' => 'Alicia']);
var_dump($u2 instanceof UserDTO);   // true


如果没有 : static 返回类型,静态分析器会推断 with() 返回 DTO,继而把 $u2->email 标注为"属性可能不存在于 DTO 上"。加上 : static 后,工具与读者都明白:对 UserDTO 调用 with() 得到的仍是 UserDTO

clone 自身并不使用 static 关键字的语义(它克隆的是对象的实际运行时类型),但"克隆并修改"这类方法的返回类型应当是 static,才能让继承关系自然工作。

6. Trait 方法与 $this::class

Trait 带来一种更微妙的情况。在 trait 内部,self:: 指向使用该 trait 的类,而非 trait 本身(因为 trait 在运行时并不具备独立的类身份)。static:: 则仍如常工作:



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

trait HasName{
    publicfunction describe(): string{
        return static::class . ' has some name';   // 解析为使用该 trait 的类
    }

    publicfunction describeSelf(): string{
        return self::class . ' has some name';     // 同样是使用该 trait 的类——trait 没有独立类身份
    }
}

class Dog{
    use HasName;
}

class Puppy extends Dog{}

(new Dog)->describe();       // "Dog has some name"
(new Dog)->describeSelf();   // "Dog has some name"
(new Puppy)->describe();     // "Puppy has some name"     ← 后期静态绑定
(new Puppy)->describeSelf(); // "Dog has some name"       ← self = 声明类 Dog


这会让一部分开发者栽跟头,他们以为 trait 与继承的行为一致。并非如此。在 trait 里,self 的含义是"使用该 trait 的那个类"(此例中是直接使用者 Dog);static 仍然是"被调用的那个类"(此例中的 Puppy)。如果 trait 的方法需要在使用者的子类之间多态地工作,必须使用 static::

PHP 8+ 还新增了 $object::class,作为 get_class($object) 的便捷写法:



1
2

$animal = new Dog();
echo $animal::class;    // "Dog"


这是运行时等价物。它永远返回对象的实际运行时类,与代码所在位置、调用方式都无关。对于已经持有的局部对象变量,$obj::class 是最清爽的写法。

需要内化的三种关键字分工

绝大多数现实决策都归结为在三样东西之间作选择:

  • • self::class——"我写在哪个类里,编译期就锁定。" 适合真正需要指向声明类、且不希望子类覆盖的场景。使用场景较少,合理的例子包括:不应多态化的内部工具方法,以及需要在整个继承层次保持稳定的常量。
  • • static::class——"调用发起于哪个类,在运行时解析。" 当方法本身是可继承的、子类应能影响其行为时使用。这是多数基类代码的默认选择:工厂、仓储模式、抽象框架方法。
  • • $object::class——"这个具体对象实例的运行时类。" 当手上已经握有一个具体对象、需要得到其精确类名时使用,等价于 get_class($object),但更易读。在所有 PHP 8+ 代码中都可用。

下面的示例把三者同时展现出来:



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

abstractclass Serializer{
    public staticfunction typeId(): string{
        return static::class;       // 运行时子类名
    }

    publicfunction debug(): array{
        return [
            'declared_in' => self::class,      // 始终为 "Serializer"
            'called_on'   => static::class,    // 实际子类
            'instance_of' => $this::class,     // 实际子类(此处与 static 一致)
        ];
    }
}

class JsonSerializer extends Serializer{}

$s = new JsonSerializer();
print_r($s->debug());
// Array (
//     [declared_in] => Serializer
//     [called_on]   => JsonSerializer
//     [instance_of] => JsonSerializer
// )


在具体对象的实例方法里,static::class 与 $this::class 通常一致。三者真正分叉的场景出现在静态方法中(那里没有 $this),或者需要在不了解继承关系的前提下检查传入对象的类时。

一个被注册表模式反噬的真实案例

下面用一个改写自真实生产事故的例子,展示这类 bug 的形态。

某个代码库有一个带注册表的基类 Command



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

abstractclass Command{
    protected static array $handlers = [];

    public staticfunction register(callable $handler): void{
        self::$handlers[static::class] = $handler;
    }

    public staticfunction dispatch(Command $command): mixed{
        $class   = $command::class;
        $handler = self::$handlers[$class] ?? null;

        if (! $handler) {
            throw new RuntimeException("No handler for $class");
        }

        return $handler($command);
    }
}

class CreateUserCommand extends Command{}
class DeleteUserCommand extends Command{}


注册是没问题的。CreateUserCommand::register(fn($c) => ...) 正确地把处理器写入 self::$handlers['CreateUserCommand']——因为 register() 内部的 static::class 解析为 CreateUserCommand

真正的陷阱很隐蔽。self::$handlers 里的 self 指向 Command 这个类——这其实正是一个共享注册表所需要的(整棵继承树共用一份注册表),处理器被正确地保存了下来。

那么 bug 出在哪?原始代码里并没有。真正让 bug 浮出水面的,是有人加入中间层继承:



1
2
3
4
5

abstractclass UserCommand extends Command{
    // 中间类,目前无方法体
}

class CreateUserCommand extends UserCommand{}


然后有人在 UserCommand 里自作聪明:



1
2
3
4
5
6
7

abstractclass UserCommand extends Command{
    protected static array $handlers = [];   // 覆盖了父类属性

    public staticfunction register(callable $handler): void{
        self::$handlers[static::class] = $handler;
    }
}


他们在 UserCommand 里再次声明了 $handlers,以为这会成为一份专属于用户命令的注册表。问题在于:此时 self::$handlers 指向 UserCommand::$handlers(解析期就绑定到了方法所在的那个类),于是注册进入的数组和派发时读取的数组就成了两个不同的数组。

修复方式是选定唯一一层来承载注册表,并始终通过它访问。然而定位这个问题花了数小时,留下的只有"为什么处理器注册成功,派发却找不到?"的困惑。答案是:两处的 self:: 指向了两个不同的数组。

核心教训是:self::$property 并不像实例属性那样具备多态性。如果基类里有静态属性,而子类又重新声明了同名属性,self:: 会根据方法所在类的不同指向不同的存储。要么把静态属性严格控制在继承层次的某一层里,要么显式改用 static::,让多态性在代码中可见。

工厂方法的标准模板

由于这一模式反复出现,下面给出可继承基类工厂方法的推荐模板:



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

abstractclass AggregateRoot{
    privatefunction __construct(
        protected readonly string $id,
        protected array $state = [],
    ) {}

    /**
     * 使用新生成的标识符创建聚合根。
     * 返回调用方对应子类的实例。
     */
    public staticfunction create(array $initialState = []): static
    {
        return new static(
            id: self::generateId(),   // ← self:基类自身的辅助函数
            state: $initialState,
        );
    }

    /**
     * 从持久化状态还原聚合根。
     * 返回调用方对应子类的实例。
     */
    public staticfunction fromState(string $id, array $state): static
    {
        return new static($id, $state);
    }

    private staticfunction generateId(): string
    {
        // 此处永远不需要多态性——使用 self 既正确又表达了意图
        return bin2hex(random_bytes(16));
    }
}

finalclass Order   extends AggregateRoot{}
finalclass Invoice extends AggregateRoot{}

$order   = Order::create(['status' => 'pending']);     // Order
$invoice = Invoice::create(['total' => 500]);          // Invoice


这里有三处值得注意:

  • • new static($id, $state)——工厂之所以能够多态,靠的就是这一句。Order::create() 返回 OrderInvoice::create() 返回 Invoice
  • • : static 返回类型——这是写给静态分析器和人类读者看的契约,明确"返回值就是被调用的那个类"。
  • • self::generateId()——这里特意使用 self::。ID 生成算法不应被子类覆盖。子类若有需要当然可以重新声明 generateId(),但基类自身的 create() 必须始终调用基类的 ID 生成器,不受子类影响。这是一个 self:: 比 static:: 更贴切的少见场景。

心智上的判断标准始终一致:是否希望子类能改写这段行为?是则使用 static::,否则使用 self::

性能:可以忽略但值得知道

偶尔有人声称 self:: 比 static:: 更快,理由是前者在编译期解析。严格来说成立,但其影响几乎可以忽略。

后期静态绑定的开销在每次调用的纳秒级别。即便在每秒循环调用一千万次的热点场景下,从 static:: 换成 self:: 也不过节省几百毫秒。除非在解析器、物理引擎或框架深处的热点循环里,否则这点差别根本不会被察觉。

比 LSB 开销更重要的是:选用的关键字是否保证了行为正确。一个"更快"却返回了错误类的程序,不能算真正的更快。

不过,有一类性能模式确实值得留意:热点循环里的 static::CONST 会在每次迭代都做一次运行时解析。如果常量在当前类里确实不变,就应该先缓存下来:



1
2
3
4
5
6
7
8
9
10

// 较慢——每次迭代都解析 static::VERSION
foreach ($items as $item) {
    $item->tag = static::VERSION;
}

// 较快——只解析一次,后续复用
$version = static::VERSION;
foreach ($items as $item) {
    $item->tag = $version;
}


这属于只在特定热点路径上生效的微优化。一个每秒只跑十次的请求处理器,完全用不到。

与该主题相关的 PHP 8+ 特性

现代 PHP 的一些特性与 static / self 组合得很好。

static 返回类型(PHP 8.0+)——专门用于表达"本方法返回的是被调用的那个类":



1

publicfunction with(array $changes): static{ ... }


在该类型出现之前,只能靠 @return static docblock 充当替代。如今它已成为正式类型,任何返回 new static(...) 或 clone $this 的方法都应使用它。

new $class(...) 动态构造——当 $class 是运行时字符串时,self 与 static 都不适用,被实例化的类就是字符串所表示的那个类:



1
2
3

publicfunction makeFromClass(string $class, array $data): object{
    return new $class($data);   // 字符串写什么,类就是什么
}


只读属性(PHP 8.1+)与 static 返回类型的组合在不可变值对象上尤其契合——返回类型正确表达"拿回的仍然是同一个子类",readonly 修饰符又杜绝了意外写入。这是 DTO 与值对象的现代写法。

一等可调用语法(PHP 8.1+)——static::method(...) 会在调用时把可调用对象绑定到当前类,遵循后期静态绑定;self::method(...) 则绑定在声明类上。规则一致,只是换了一种表达方式:



1
2
3
4
5
6
7
8
9
10
11
12

abstractclass Formatter{
    publicfunction pipeline(): array{
        return [
            static::class . '::normalize',   // 延迟解析,子类可覆盖
            static::normalize(...),          // 等效,写成 callable 形式
            self::class . '::escape',        // 锁定到 Formatter::escape
        ];
    }

    protected staticfunction normalize(string $s): string{ return trim($s); }
    protected staticfunction escape(string $s): string{ return htmlspecialchars($s); }
}


决策框架

写下 self:: 或 static:: 之前,可以依次自问下列问题。

  1. 1. 这段代码是否位于 final 类或永远不会被继承的类?——二者都可用,约定上选 self:: 以表达意图。该类不会有子类,区别在此没有实际后果。
  2. 2. 这段代码是否位于打算被继承的基类?——几乎总是 static::。例外情况是被引用的对象属于实现细节,不应被多态化(比如前文的 generateId())。
  3. 3. 这是一个实例方法,且手头有一个具体对象?——优先使用 $this::class 或 $this->method() 作运行时类型查找,表达最直接。
  4. 4. 是否在写一个应返回子类实例的工厂方法?——始终使用 new static(...),并配 : static 返回类型。
  5. 5. 是否覆盖了常量并期望基类能看到这次覆盖?——必须使用 static::CONSTself::CONST 会悄无声息地返回基类的值。
  6. 6. 阅读既有代码时遇到 self::,并且正准备继承它?——仔细辨析原作者到底是有意"锁定在当前类",还是只是习惯性地写了 self::。两者都很常见。

简明 Q&A

Q:有没有场景 self:: 严格优于 static::
有三种。第一,在禁止继承的 final 类里,self:: 向读者传达了"无需考虑子类"的意图;第二,方法体依赖某个绝不可被覆盖的具体实现——少见但确实存在;第三,私有方法本就无法被覆盖,用 self:: 更能忠实表达意图。除此之外,static:: 更安全。

Q:parent:: 是什么语义,与这套机制如何衔接?
parent:: 指向代码所在类的父类——是 self:: 的"向上"版本。它同样在解析期确定,主要用于调用 parent::__construct() 或扩展父类方法。它没有对应的延迟绑定形式(不存在 static_parent::),这在某些场合会让人略感不便。

Q:Laravel 模型里到处都是 new self(...),是不是有问题?
多数情况不会有问题,因为 Eloquent 内部处理了大部分细节——它的 newInstance() 使用 static::。但如果在模型上自定义了工厂方法并在其中写了 new self(...),一旦需要继承(例如单表继承或类似模式),这些方法就会失效。应逐一审查并替换为 new static(...) 加 : static 返回类型。

Q:static:: 能引用非静态的成员吗?
可以。"后期静态绑定"中的 static 指的是解析机制,而不是被引用对象的静态性。static::someMethod() 既能调用静态方法,也能调用非静态方法(不过以静态方式调用非静态方法通常是错误用法)。更常见的用法是 static::class——取得运行时类名后交由其他 API 使用。

Q:如何通过测试捕获这类 bug?
最可靠的方式是在测试里给基类写一个子类,再验证方法返回的是子类实例,或常量解析为子类的值。仅覆盖基类自身的测试无法捕获 self:: 与 static:: 的差异——这种差异只在继承中显现。这恰恰是"只对基类做隔离测试"会给人虚假信心的一类场景。

Q:PHPStan、Psalm 对此怎么看?
两者都理解 static 返回类型,能在方法声明 : static 时正确推断子类类型。它们(在较严格的级别下)还会对非 final 类里的 new self(...) 提示,建议改为 new static(...)。把 PHPStan 调到 level 6+、Psalm 调到 level 3+,多数此类问题会被自动暴露。

Q:这件事只与面向对象相关吗?还是在函数式/过程式代码中也有影响?
只与 OOP 相关,更具体地说只与继承相关。如果代码库里没有类继承——所有类都 final、靠组合而非继承——self 与 static 的差别对实际开发就只是学术话题。final 类里统一用 self:: 保持一致即可。差异只有在一个类继承另一个类时才有实质意义。

结语

self:: 与 static:: 之间的差别,是 PHP 语言逐步演进所留下的痕迹。在后期静态绑定(PHP 5.3)出现之前,self:: 是唯一选择,静态方法的继承在当时几乎是坏的——根本无法写出真正多态的工厂。LSB 修好了这件事,却让两个关键字同时保留下来,留给开发者自行判断用哪一个。

实用原则是:在基类里拿不准时,优先 static::。它是让代码在被继承时依旧正确运行的关键字。self:: 是一把更窄的工具,服务于更窄的目的——把行为锁死在声明类,通常用于 final 类或内部辅助方法。

这个决定很小,仅仅两个字符的差别。但和所有与多态性相关的决定一样,它的影响会累积。一个始终使用 static:: 的基类会成为子类的一块干净底座;一个习惯性写 self:: 的基类,则会成为所有子类都会静默出错、且只有在生产环境才暴露的温床。

因此要有意识地选择、审计既有代码、在每一个工厂或流式方法上都加 : static 返回类型。那些因此未被写出的 bug,所节省的代价远超花在思考上的时间。

速查卡

心智模型:self:: 回答"代码写在哪里",static:: 回答"调用来自哪里"。

工厂方法的标准形态:



1
2
3

public staticfunction create(...): static{
    return new static(...);
}


差异会产生影响的六个位置:

  • • new self 与 new static——工厂方法与多态
  • • self::CONST 与 static::CONST——需要被子类覆盖的常量
  • • self::method() 与 static::method()——调用可被覆盖的辅助方法
  • • instanceof self 与 instanceof static——基类内的类型检查
  • • 返回类型 : self 与 : static——静态分析器所理解的契约
  • • Trait 内部——self 指向使用该 trait 的类,依旧在解析期锁定

三元查找对照:

  • • self::class——代码声明所在类,编译期
  • • static::class——调用发起的类,运行时(后期静态绑定)
  • • $object::class——具体对象的运行时类(PHP 8+)

在 final 类里两者都可用,约定选 self::,因为继承已不可能发生。在打算被继承的基类里,默认选 static::。例外是那些属于"不应被覆盖的实现细节"的地方——此时 self:: 能把意图清楚地传达给下一位读者。

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-07-03 06:44:03 HTTP/2.0 GET : https://f.mffb.com.cn/a/495510.html
  2. 运行时间 : 0.297615s [ 吞吐率:3.36req/s ] 内存消耗:4,848.62kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=9c78bcc6bdecd1b0090ad3f3f864d5aa
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000592s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000661s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.026649s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.008199s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000623s ]
  6. SELECT * FROM `set` [ RunTime:0.000210s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000583s ]
  8. SELECT * FROM `article` WHERE `id` = 495510 LIMIT 1 [ RunTime:0.014281s ]
  9. UPDATE `article` SET `lasttime` = 1783032243 WHERE `id` = 495510 [ RunTime:0.022138s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.011070s ]
  11. SELECT * FROM `article` WHERE `id` < 495510 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.010161s ]
  12. SELECT * FROM `article` WHERE `id` > 495510 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.003126s ]
  13. SELECT * FROM `article` WHERE `id` < 495510 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.017169s ]
  14. SELECT * FROM `article` WHERE `id` < 495510 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.041832s ]
  15. SELECT * FROM `article` WHERE `id` < 495510 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.068808s ]
0.299229s