12: 高级
Phlo 故意保持模块化。您可以保持应用程序小巧,仅激活所需的资源,或组合多个源路径和资源组。
12.1: 应用程序代码和运行时资源
应用特定的代码应放在应用本身中。不要将其放在 /srv/phlo/resources/ 中。
/srv/phlo/resources/ 是 Phlo 运行时目录:可以在多个应用之间共享的框架范围资源,并且与运行时一起有意维护。只有通用的、稳定的代码才能放在那里。
如果您想在应用之间共享代码,请首先创建一个明确的共享模块或应用库路径,并指定明确的所有者。只有在代码确实是框架功能时,才可以将其提升到 Phlo 运行时目录。
运行时资源可以提供对象、函数、样式或脚本。文件顶部的元数据有助于 Phlo Control Center 和手册:
@ summary: Send app notifications
@ package: notifications
@ frontend: false
@ backend: true
method send($message){
return HTTP(%creds->notify->url, POST: ['message' => $message])
}12.2: 多个源路径
保持默认设置简单:应用程序源代码位于应用程序路径中。仅在代码库确实需要共享时才添加额外路径。
路径选择应保持可预测:
- 应用程序源代码在
/srv/example.nl/ - 运行时在
/srv/phlo/ - 发布在
/srv/example.nl/release/ - 数据和凭据在
/srv/example.nl/data/
12.3: 与现有的 PHP 集成
在现有的 PHP 旁边使用 Phlo,通过加载运行时并使 Phlo 入口点仅负责应用处理的 routes。现有的静态文件仍然由 webserver 直接提供服务。
<?php
require('/srv/phlo/phlo.php');
phlo_app (
id: 'Legacy',
host: 'dev.legacy.test',
build: true,
debug: true,
app: '/srv/legacy/',
);12.4: 安全与访客
对于公共网站,通常的基线是:
{
"resources": [
"cookies",
"security/security",
"security/token",
"session",
"useragent",
"visitors",
"phlo.async",
"DOM/form"
]
}
对于本地开发,您可以排除跟踪:
{
"exclude": [
"visitors",
"useragent",
"wsCast"
]
}12.5: Cookiewall:GDPR 同意
DOM/cookiewall 是一个内置的、微妙的同意横幅。通过以下 3 个步骤激活它:
1. 在 data/app.json 中添加资源:
{ "resources": [..., "DOM/cookiewall"] }
2. 在您的布局中添加横幅:
view layout:
<body>
{{ %cookiewall->banner }}
<main>...</main>
</body>
当访客尚未做出选择时,横幅才会出现。提供两个按钮:“仅限必要”和“接受”。选择存储在一个名为 cookieChoice 的 cookie 中('essential' 或 'all'),有效期为 1 年。
3. 在跟踪周围添加保护:
<if %cookiewall->canTrack>
<script src="https://analytics.example.com/script.js"></script>
</if>
| 方法 | 返回值 |
|---|---|
%cookiewall->hasChosen() |
一旦访客做出选择,返回 true |
%cookiewall->canTrack |
仅在选择为 'all' 时返回 true |
%cookiewall->canAnalytics |
canTrack 的别名,在分析桥接中语义上有用 |
%cookiewall->choice |
'essential' / 'all' / null |
多语言变体:DOM/cookiewall.translated(使用 {nl: ...} 简写表示横幅文本)。
12.6: 工作模式
默认情况下,Phlo 每个请求运行一次:PHP 进程启动,处理请求,进程结束。在 phlo_app(...) 中使用 thread: true 时,运行时在请求之间保持在内存中,旨在用于 FrankenPHP、ReactPHP 或 RoadRunner。
性能提升非常显著(每个请求无需启动),但有三条规则适用:
1. 在 HTTP 路径中不要使用 die() 或 exit()。 两者都会终止整个 worker,而不仅仅是当前请求。使用 return 或让终止调用(view()、apply()、location())发送响应。
2. 静态属性中不要存储请求状态。 静态属性在请求之间存活。请求 A 的数据会泄漏到请求 B。静态属性仅适用于类结构或对所有请求都相同的计算元数据,而不适用于会话、用户、有效负载、时间或数据库状态。
3. 用 $objPers = true 标记长生命周期对象。 默认情况下,Phlo 在请求之间清除其实例映射。对于您明确希望重用的对象(数据库连接、预处理语句),设置 $this->objPers = true,以便清理时不影响它们。
与 build: true 结合使用是 不允许的:构建在请求之间写入文件,而在 worker 中这会导致竞争条件。如果您同时启用这两者,Phlo 会抛出运行时错误。
12.7: 在不分叉的情况下修改资源
有时您希望共享资源在一个应用程序中表现得略有不同,而不必复制或更改该资源。在任何 .phlo 文件中,您可以通过将节点命名为 %<class>.<node> 来注入或覆盖 不同 类中的节点:
static %visitors.table = 'control.visitors'
prop %visitors.db = 'control'
method %model.greet => 'hi'
第一行覆盖了 visitors 模型的 static $table;第二行向 visitors 添加了一个 db prop;第三行向 model 添加了一个 greet 方法。在构建过程中,编译器会去掉 %<class>. 前缀,并将节点写入 <class>:具有该名称的现有节点将被 覆盖,一个新的节点将被添加。目标类必须是构建的一部分(其资源已加载),否则修饰符将被静默忽略。保持节点类型与您替换的类型相同(static 替换为 static,prop 替换为 prop):整个节点将被交换。
一个实际的例子:让共享的 visitors 模型写入一个中央分析数据库,而应用程序中的所有其他查询保持在应用程序自己的连接上:
static %visitors.table = 'control.visitors'
这使得共享资源保持中立,同时每个应用程序都给它自己的解释。
12.8: 文件元数据:完整的 @ 引用
每个 .phlo 文件可以以 @ key: value 行开头。任何键都作为文件元数据存储;这些具有引擎或工具的含义:
| 键 | 效果 |
|---|---|
@ class: |
重写 PHP 类名 |
@ extends: |
PHP 继承(默认:obj) |
@ implements: |
PHP 接口,以逗号分隔 |
@ use: |
PHP 使用语句(Full\Name as Alias) |
@ namespace: |
PHP 命名空间 |
@ type: |
class(默认),abstract class,interface 或 trait |
@ summary: |
一行描述,在手册、反射和 Phlo Control Center 中显示 |
@ package: |
工具的组名 |
@ frontend: / @ backend: |
标记为仅前端或后端的资源 |
@ requires: |
依赖项,在资源启用时解析;name? 是可选的,php-ext: 和 creds: 条目是信息性 |
@ provides: / @ binds: |
提供的前端 API / 连接的选择器;供 reflect::selectorGraph 使用 |
@ tags: |
自由格式标签,在反射索引中显示 |
@ advice: |
开发者指导,在 reflect::objectIndex 中显示 |
12.9: 最佳实践
- 保持入口点明确;避免隐藏配置。
- 让发布输出来自
build::release。 - 切勿在源文件中放置凭据。
- 使用反射来验证资源、路由和函数。
- 仅在多个应用程序确实受益时才添加抽象。