第108章 如何开发 SAI Extension
第107章建立了 SAI Object,解决了 SAI 如何表示对象、属性、方法、关系和状态的问题。
但是,一个完整的 SAI Framework 不可能把所有功能都直接写进 Core。
例如以后可能增加:
Temperature Extension
Robot Extension
Vehicle Extension
Industrial Extension
Web Extension
File Extension
Sensor Extension
Device Extension
Detection Extension
Learning Extension
这些功能应该能够:
- 独立存在
- 独立注册
- 独立加载
- 独立配置
- 独立启动
- 独立停止
- 独立卸载
因此需要 Extension System。
本章核心结构:
Extension
│
├── Interface
├── Directory
├── Registry
├── Manager
├── Loading
├── Configuration
└── Runtime
1. Extension Interface
1.1 Extension 定义
Extension 是 SAI Framework 中用于扩展 Core 功能的独立功能单元。
可以定义为:
Extension =
Identity
+
Function
+
Interface
+
Lifecycle
+
Configuration
Extension 本身不是 Individual,也不是 Module、Engine。
它更接近于:
一个可以被 Framework 注册、加载、启动、停止和卸载的扩展载体。
1.2 ExtensionInterface
建立统一接口:
<?php
interface ExtensionInterface
{
public function getId();
public function getName();
public function getVersion();
public function initialize();
public function start();
public function stop();
public function shutdown();
public function getState();
}
这样 Framework 就可以统一处理不同 Extension。
例如:
RobotExtension
VehicleExtension
SensorExtension
LearningExtension
都必须实现:
ExtensionInterface
1.3 Extension 生命周期
一个 Extension 可以经过:
NEW
↓
REGISTERED
↓
LOADED
↓
INITIALIZED
↓
READY
↓
RUNNING
↓
STOPPING
↓
STOPPED
↓
UNLOADED
异常状态:
ERROR
CONFLICT
DISABLED
INVALID
UNKNOWN
2. Extension Directory
2.1 为什么需要 Extension Directory
Extension 不能全部放在 Framework Core 中。
因此建立独立目录:
sai/
│
├── core/
│
├── modules/
│
├── engines/
│
├── objects/
│
└── extensions/
例如:
extensions/
│
├── RobotExtension/
│ ├── Extension.php
│ ├── config.php
│ └── README.md
│
├── VehicleExtension/
│ ├── Extension.php
│ └── config.php
│
└── TemperatureExtension/
├── Extension.php
└── config.php
2.2 一个 Extension 的基本目录
例如:
TemperatureExtension/
│
├── Extension.php
├── config.php
└── engines/
└── TemperatureEngine.php
如果 Extension 需要 Object:
TemperatureExtension/
│
├── Extension.php
├── config.php
├── engines/
│ └── TemperatureEngine.php
└── objects/
└── TemperatureObject.php
因此 Extension 可以作为一个功能集合的载体。
3. Extension Registry
3.1 Registry 定义
Extension Registry 用于记录系统中有哪些 Extension。
例如:
$registry = array(
'temperature' => array(
'id' => 'temperature',
'name' => 'Temperature Extension',
'version' => '1.0.0',
'class' => 'TemperatureExtension',
'path' => 'extensions/TemperatureExtension/Extension.php',
'enabled' => true,
'state' => 'REGISTERED'
)
);
3.2 Registry 的作用
Registry 主要记录:
id
name
version
class
path
type
dependencies
configuration
enabled
state
例如:
TemperatureExtension
│
├── id = temperature
├── version = 1.0.0
├── class = TemperatureExtension
├── path = extensions/TemperatureExtension/Extension.php
├── enabled = true
└── state = REGISTERED
3.3 Registry ≠ Manager
必须区分:
Registry
=
记录有哪些 Extension
而:
Manager
=
管理当前 Extension
例如:
ExtensionRegistry
│
├── RobotExtension
├── VehicleExtension
├── TemperatureExtension
└── SensorExtension
运行时:
ExtensionManager
│
├── RobotExtension
└── TemperatureExtension
所以:
Registered ≠ Loaded
Loaded ≠ Running
4. Extension Manager
4.1 ExtensionManager 定义
ExtensionManager 是 Extension 的运行管理组件。
主要负责:
register
get
load
initialize
start
stop
shutdown
unload
4.2 基本代码
<?php
class ExtensionManager
{
protected $extensions = array();
public function register(ExtensionInterface $extension)
{
$this->extensions[$extension->getId()] = $extension;
return true;
}
public function get($id)
{
if (!isset($this->extensions[$id])) {
return null;
}
return $this->extensions[$id];
}
public function exists($id)
{
return isset($this->extensions[$id]);
}
public function start($id)
{
$extension = $this->get($id);
if ($extension === null) {
return false;
}
return $extension->start();
}
public function stop($id)
{
$extension = $this->get($id);
if ($extension === null) {
return false;
}
return $extension->stop();
}
public function all()
{
return $this->extensions;
}
}
5. Extension Loading
5.1 Loading 定义
Extension Loading 是 Framework 把一个已经登记的 Extension 转换成运行对象的过程。
基本流程:
Registry
↓
Read Configuration
↓
Check Enabled
↓
Check Directory
↓
Check File
↓
Load Class
↓
Check Interface
↓
Create Object
↓
Initialize
↓
READY
5.2 File Check
首先确认 Extension 文件存在:
if (!file_exists($path)) {
return false;
}
不能因为 Registry 中存在记录,就认为 Extension 一定可用。
5.3 Class Check
加载文件:
require_once $path;
然后检查:
if (!class_exists($className)) {
return false;
}
5.4 Interface Check
必须确认:
$interfaces = class_implements($className);
if (!isset($interfaces['ExtensionInterface'])) {
return false;
}
这样可以避免一个普通 PHP Class 被错误当成 Extension。
5.5 Create Object
检查通过后:
$extension = new $className();
然后:
NEW
↓
INITIALIZING
↓
READY
6. Extension Configuration
6.1 Configuration 定义
Extension 不应该把所有参数直接写死在 Class 中。
例如:
TemperatureExtension
可能需要:
temperature_limit
check_interval
enabled
logging
因此需要 Configuration。
6.2 config.php
例如:
<?php
return array(
'enabled' => true,
'temperature_limit' => 85,
'check_interval' => 10,
'logging' => true
);
6.3 Configuration 结构
可以统一:
Extension Configuration
│
├── enabled
├── version
├── dependencies
├── parameters
├── runtime
└── logging
例如:
$config = array(
'enabled' => true,
'version' => '1.0.0',
'parameters' => array(
'temperature_limit' => 85
),
'runtime' => array(
'interval' => 10
),
'logging' => true
);
6.4 Configuration ≠ Cognition
Configuration 只是参数。
例如:
temperature_limit = 85
表示系统配置。
真正的运行判断:
temperature = 92
limit = 85
92 > 85
↓
HIGH
属于 Engine / Rule 等运行逻辑。
所以:
Configuration ≠ Rule
Configuration ≠ Cognition
Configuration ≠ Reasoning
7. Extension Runtime
7.1 Runtime 定义
Extension Runtime 是 Extension 被加载并开始提供功能后的运行阶段。
例如:
Framework
↓
ExtensionManager
↓
TemperatureExtension
↓
TemperatureEngine
↓
Input
↓
Processing
↓
Result
7.2 Extension 可以包含 Engine
例如:
TemperatureExtension
│
├── TemperatureEngine
├── TemperatureObject
└── TemperatureRule
因此:
Extension
├── Module
├── Engine
├── Object
├── Rule
└── Adapter
具体包含什么,由 Extension 自己的功能需求决定。
7.3 Extension Runtime 不等于 Individual Runtime
这是非常重要的边界。
Individual Runtime
=
运行 SAI Individual 的认知生命周期
而:
Extension Runtime
=
运行某个扩展功能
例如:
Individual_A
↓
Cognition
↓
Reasoning
↓
Decision
↓
TemperatureExtension
↓
TemperatureEngine
Extension 是 Individual 可以使用的功能资源之一。
8. 完整 Extension 示例
现在开发一个最简单的:
TemperatureExtension
功能:
输入 temperature
输入 limit
判断 temperature 是否超过 limit
返回 HIGH / NORMAL
整个过程使用:
Extension
+
Engine
+
Configuration
+
Manager
不使用任何生成式模型机制。
8.1 项目目录
simple-sai/
│
├── index.php
│
├── core/
│ ├── ExtensionInterface.php
│ └── ExtensionManager.php
│
└── extensions/
│
└── TemperatureExtension/
├── Extension.php
├── config.php
└── TemperatureEngine.php
8.2 ExtensionInterface.php
<?php
interface ExtensionInterface
{
public function getId();
public function getName();
public function getVersion();
public function initialize();
public function start();
public function stop();
public function shutdown();
public function getState();
}
8.3 TemperatureEngine.php
<?php
class TemperatureEngine
{
protected $limit = 85;
public function __construct($config = array())
{
if (isset($config['temperature_limit'])) {
$this->limit = $config['temperature_limit'];
}
}
public function execute($temperature)
{
if (!is_numeric($temperature)) {
return array(
'state' => 'INVALID',
'error' => 'TEMPERATURE_INVALID'
);
}
if ($temperature > $this->limit) {
return array(
'state' => 'SUCCESS',
'level' => 'HIGH',
'temperature' => $temperature,
'limit' => $this->limit
);
}
return array(
'state' => 'SUCCESS',
'level' => 'NORMAL',
'temperature' => $temperature,
'limit' => $this->limit
);
}
}
8.4 config.php
<?php
return array(
'enabled' => true,
'temperature_limit' => 85
);
8.5 Extension.php
<?php
require_once dirname(__FILE__) . '/../../core/ExtensionInterface.php';
require_once dirname(__FILE__) . '/TemperatureEngine.php';
class TemperatureExtension implements ExtensionInterface
{
protected $id = 'temperature';
protected $name = 'Temperature Extension';
protected $version = '1.0.0';
protected $state = 'NEW';
protected $config = array();
protected $engine;
public function getId()
{
return $this->id;
}
public function getName()
{
return $this->name;
}
public function getVersion()
{
return $this->version;
}
public function initialize()
{
$this->state = 'INITIALIZING';
$configFile = dirname(__FILE__) . '/config.php';
if (!file_exists($configFile)) {
$this->state = 'ERROR';
return false;
}
$this->config = require $configFile;
if (isset($this->config['enabled'])
&& !$this->config['enabled']) {
$this->state = 'DISABLED';
return false;
}
$this->engine = new TemperatureEngine(
$this->config
);
$this->state = 'READY';
return true;
}
public function start()
{
if ($this->state !== 'READY') {
return false;
}
$this->state = 'RUNNING';
return true;
}
public function stop()
{
if ($this->state !== 'RUNNING') {
return false;
}
$this->state = 'STOPPED';
return true;
}
public function shutdown()
{
$this->engine = null;
$this->state = 'SHUTDOWN';
return true;
}
public function getState()
{
return $this->state;
}
public function execute($temperature)
{
if ($this->state !== 'RUNNING') {
return array(
'state' => 'NOT_RUNNING'
);
}
return $this->engine->execute($temperature);
}
}
9. ExtensionManager 完整示例
<?php
class ExtensionManager
{
protected $extensions = array();
public function register(ExtensionInterface $extension)
{
$this->extensions[$extension->getId()] = $extension;
return true;
}
public function get($id)
{
if (!isset($this->extensions[$id])) {
return null;
}
return $this->extensions[$id];
}
public function initialize($id)
{
$extension = $this->get($id);
if ($extension === null) {
return false;
}
return $extension->initialize();
}
public function start($id)
{
$extension = $this->get($id);
if ($extension === null) {
return false;
}
return $extension->start();
}
public function stop($id)
{
$extension = $this->get($id);
if ($extension === null) {
return false;
}
return $extension->stop();
}
}
10. index.php
<?php
require_once 'core/ExtensionInterface.php';
require_once 'core/ExtensionManager.php';
require_once
'extensions/TemperatureExtension/Extension.php';
$manager = new ExtensionManager();
$extension = new TemperatureExtension();
$manager->register($extension);
$manager->initialize('temperature');
$manager->start('temperature');
$result = $extension->execute(92);
echo '<pre>';
print_r($result);
echo '</pre>';
$manager->stop('temperature');
$extension->shutdown();
11. 完整运行过程
输入:
temperature = 92
配置:
temperature_limit = 85
运行:
92 > 85
得到:
state = SUCCESS
level = HIGH
temperature = 92
limit = 85
完整执行过程:
index.php
↓
ExtensionManager
↓
TemperatureExtension
↓
initialize()
↓
读取 config.php
↓
TemperatureEngine
↓
start()
↓
execute(92)
↓
92 > 85
↓
HIGH
↓
Result
12. Extension 与 Framework 的完整关系
到第108章,SAI Framework 的结构进一步形成:
SAI Framework
│
├── Kernel
│
├── Individual
│
├── Module
│
├── Engine
│
├── Object
│
├── Extension
│
├── Event
│
├── Task
│
├── Memory
│
├── Renderer
│
└── Adapter
其中 Extension 可以承载其他组件:
Extension
│
├── Module
│
├── Engine
│
├── Object
│
├── Rule
│
├── Renderer
│
└── Adapter
这使 Framework Core 不需要因为增加一个新功能而不断修改核心结构。
13. Extension 完整生命周期
最终可以统一为:
NEW
↓
REGISTERED
↓
LOADED
↓
INITIALIZING
↓
READY
↓
RUNNING
↓
STOPPING
↓
STOPPED
↓
SHUTDOWN
↓
UNLOADED
异常:
ERROR
CONFLICT
DISABLED
INVALID
UNKNOWN
14. Extension 与其他组件的区别
这一章之后几个概念需要严格区分:
| 组件 | 主要职责 |
|---|---|
| Individual | SAI 个体运行主体 |
| Module | 功能组织单元 |
| Engine | 具体功能执行 |
| Object | 实体结构表示 |
| Extension | 功能扩展载体 |
| Registry | 登记组件 |
| Manager | 管理组件 |
| Adapter | 连接外部环境 |
| Renderer | 转换外部表现形式 |
最重要的关系:
Extension
↓
承载
↓
Module / Engine / Object / Rule / Adapter / Renderer
而:
Registry
=
登记
Manager
=
管理
Runtime
=
运行
本章核心定义
Extension Interface
规定 Extension 必须具备的统一生命周期和基本身份接口。
Extension Directory
保存 Extension 独立代码、配置及其相关组件的目录结构。
Extension Registry
记录 Extension 身份、Class、路径、版本、依赖、配置和状态的登记结构。
Extension Manager
负责 Extension 注册、获取、初始化、启动、停止和关闭等运行管理。
Extension Loading
将 Registry 中登记的 Extension 检查、载入、实例化并初始化为可运行对象的过程。
Extension Configuration
为 Extension 提供启用状态、参数、依赖和运行配置的结构化参数。
Extension Runtime
Extension 被初始化并进入运行状态后实际提供功能的运行过程。
本章最终模型
SAI Framework
│
↓
Extension Registry
│
↓
Extension Manager
│
↓
Extension
│
┌──────────────┼──────────────┐
↓ ↓ ↓
Module Engine Object
│ │ │
└──────────────┼──────────────┘
↓
Runtime
│
↓
Result
Extension 的核心价值可以概括为:
Core
↓
Extension Interface
↓
Extension
↓
独立功能
↓
注册
↓
加载
↓
配置
↓
运行
↓
停止 / 卸载
因此,第108章建立的是 SAI Framework 的动态扩展机制:
Core 提供稳定基础,Extension 提供可注册、可加载、可配置、可运行、可停止的外部功能。
并且 Extension 本身仍然只是功能扩展机制,它不承担 Cognition、Reasoning、Decision 等认知职责,也不改变 SAI 的符号、规则、对象、关系和离散计算基础。