9: 实例管理

Phlo 使用其自己的 instance manager 来高效且可预测地初始化和重用对象。该系统确定 何时运行控制器代码,实例如何存储,以及如何防止循环引用。

9.1: 基础知识

当你定义一个 .phlo 文件时,构建阶段将其转换为一个类。
每次通过 %name 调用一个对象时,都会经过 instance manager (phlo()/phlo/phlo.php 中)。

示例:

prop title = 'Welcome'

route GET home => $this->main

method main => view($this->home)

view home:
<h1>$this->title</h1>

当请求路由 /home 时:

  1. 实例管理器检查该类的实例是否已经存在。
  2. 如果不存在,则 创建并存储
  3. 创建后,控制器代码 运行(见 §8.2)。
  4. 然后调用请求的方法。

9.2: 控制器代码

.phlo 文件中,属于 routepropstaticmethodfunctionview<style><script> 的所有代码都是 controller code。 这段代码在 实例化后 运行,一旦实例完全存在。

示例:

prop ready = false

%session->start()
$this->ready = true

最后两行是 controller code,因为它们位于顶层。

9.3: `__handle()` 的角色

Phlo 为每个类生成一个特殊的 __handle() 方法。实例管理器会在 通过 %name 请求实例时 调用它。

__handle()

您永远不会自己调用或重写 __handle();它是生成的类和实例管理器的一部分。

9.4: 惰性初始化

因为控制器代码仅在构造后运行,实例可以相互引用而不会触发不必要的递归创建。

示例:

a.phlo:

prop message = 'A ready'

b.phlo:

prop message = 'B ready'

main.phlo:

route GET test => $this->show

method show {
  dx(%a->message, %b->message)
}

9.5: obj 基类:powertools

每个编译的类都扩展了 obj,而 obj 不仅仅是 __get/__set。这些是当类需要动态行为时你可以使用的工具。

拦截钩子。 实现 objCallobjGetobjSet 来捕获访问链。返回 null 会继续执行正常行为;任何非 null 的返回会短路:

method objGet($key) => $this->cache[$key] ?? null

method objCall($method, ...$args) => str_starts_with($method, 'find') ? $this->finder($method, $args) : null

method objSet($key, $value) => $key === 'id' ? true : null

objGet 在每次读取时会在数据/闭包/方法/属性查找之前运行,objCall 在每次未知方法调用时运行,objSet 在每次写入之前运行(非 null 的返回会吞掉写入)。这就是装饰器、延迟加载和只读保护背后的机制。

绑定闭包。 分配一个闭包,它会绑定到实例上:$obj->greet = fn() => "Hi $this->name",之后 $obj->greet() 运行时 $this 被绑定。适合于不需要子类化的每个实例行为。

数据 API。 objImport(name: 'x', age: 3) 批量分配并返回 $this(可链式调用)。objKeys()objValues()objLength() 检查数据;objClear() 清空数据。迭代一个 obj(foreach $record AS $key => $value)和 json_encode($record) 精确暴露存储的数据。每次写入都会翻转 objChanged,这是 ORM 用来决定 objSave 是否写入任何内容的脏标志。

计算属性缓存。 prop x => ... 在首次访问时缓存;参数形式按参数集缓存。计算静态属性也是如此,按类缓存。

工作者持久性。 prop objPers = true 使实例在工作模式请求之间存活:phlo() 注册表仅在每次请求重置时保留 objPers 实例。适用于数据库连接和解析的配置;不适用于任何请求或用户范围的内容。

课程。 父类中的普通属性会遮蔽子类中的计算属性。抽象父类中的 prop dir = void 编译为一个真实的 PHP 属性,因此子类的 prop dir => guide 获取器永远不会被查询:$this->dir 默默读取 void。当子类必须用计算属性重写时,也要将父属性声明为计算属性:prop dir => void

9.6: 最佳实践

我们使用必要的cookie来使该网站正常工作。在您的许可下,我们还使用分析工具来改善网站。