首页 理论 架构 工程 文档 白皮书 著作 研究 案例 下载 博客 关于 开始使用 →

第5章 SAI Framework 开发环境

第5章 SAI Framework 开发环境

本章大纲

  1. PHP 环境
  2. PHP OOP
  3. 项目目录
  4. PHP Namespace
  5. Autoload
  6. 配置文件
  7. Storage
  8. Extension
  9. 开发调试
  10. 错误处理
  11. 第一个 SAI 项目
  12. 本章运行验证

5.1 PHP 环境

SAI Framework 的基础开发语言采用 PHP

选择 PHP OOP 作为 SAI Framework 的工程基础,并不是因为 SAI 属于 Web,而是因为 PHP 本身具备比较完整的:

类
对象
接口
继承
封装
命名空间
异常
文件系统
模块化

等面向对象开发能力。

因此,一个最基本的 SAI 开发环境可以是:

操作系统
   ↓
PHP
   ↓
SAI Framework
   ↓
Individual

最简单的环境只需要 PHP 即可。

例如:

PHP 8.x

就可以运行基础 SAI 程序。

如果项目需要 Web 应用,再增加:

Web Server

例如:

Apache
Nginx
PHP Built-in Server

但需要明确:

Web Server 是 SAI Web 应用的运行环境,不是 SAI Framework 本身的组成条件。


5.2 PHP OOP

SAI Framework 的核心对象都可以通过 PHP Class 表达。

例如:

class ObjectEntity
{
    protected $id;
    protected $name;

    public function __construct($id, $name)
    {
        $this->id = $id;
        $this->name = $name;
    }

    public function getId()
    {
        return $this->id;
    }

    public function getName()
    {
        return $this->name;
    }
}

创建对象:

$room = new ObjectEntity(
    'room_001',
    'Room'
);

这样:

ObjectEntity
      │
      └── room_001

就成为一个实际运行中的 PHP Object。

SAI Framework 可以进一步把不同概念分别建立为 Class:

Information
Element
Object
Property
Relation
Rule
Fact
State
Memory
Experience
Ability
Engine
Manager
Central
Individual

例如:

class Property
{
    protected $name;
    protected $value;

    public function __construct($name, $value)
    {
        $this->name  = $name;
        $this->value = $value;
    }
}

这就是 SAI 最基础的对象建模方式。


5.3 项目目录

SAI Framework 需要一个清晰的目录结构。

本教程采用下面的基础结构:

sai/
│
├── app/
│   ├── Core/
│   ├── Information/
│   ├── Scene/
│   ├── Individual/
│   ├── Central/
│   ├── Element/
│   ├── Object/
│   ├── Relation/
│   ├── Rule/
│   ├── Perception/
│   ├── Cognition/
│   ├── Memory/
│   ├── Reasoning/
│   ├── Decision/
│   ├── Behavior/
│   ├── Expression/
│   ├── Template/
│   ├── Renderer/
│   ├── Adapter/
│   ├── Device/
│   ├── Feedback/
│   ├── Experience/
│   ├── Learning/
│   └── Extension/
│
├── config/
│
├── storage/
│
├── extensions/
│
├── templates/
│
├── public/
│   └── index.php
│
└── bootstrap.php

需要特别注意:

这只是本教程建立的架构目录,本章示例中的目录和文件属于教程设计;除非实际创建并运行,否则不能把它们描述为已经存在的项目。


目录职责

app/

核心 PHP 类。

app/

是 SAI Framework 的主要代码区域。


config/

配置:

config/
├── app.php
├── individual.php
├── memory.php
└── device.php

storage/

运行过程中产生的数据:

storage/
├── memory/
├── experience/
├── state/
├── logs/
└── runtime/

extensions/

扩展:

extensions/
├── engine/
├── adapter/
├── renderer/
├── device/
└── custom/

templates/

表现模板:

templates/
├── web/
├── api/
├── ui/
└── device/

public/

如果使用 Web:

public/index.php

可以作为 Web 入口。


5.4 PHP Namespace

当 SAI Framework 的 Class 数量越来越多时,如果所有类都处于全局命名空间,就容易出现名称冲突。

例如:

class Object
{
}

但是 PHP 或其他程序中可能已经存在同名定义。

因此 SAI Framework 使用 Namespace。

例如:

namespace SAI\Object;

class ObjectEntity
{
}

使用:

use SAI\Object\ObjectEntity;

$object = new ObjectEntity();

这样可以形成清晰的模块边界:

SAI
├── Information
├── Object
├── Relation
├── Memory
├── Reasoning
├── Decision
└── Behavior

例如:

namespace SAI\Memory;

class Memory
{
}

以及:

namespace SAI\Reasoning;

class ReasoningEngine
{
}

Namespace 不只是解决名称冲突。

它还可以表达:

一个 Class 属于 SAI Framework 的哪个模块。


5.5 Autoload

如果一个项目只有几个 PHP 文件,可以手动:

require_once 'Object.php';
require_once 'Memory.php';
require_once 'Rule.php';

但是 SAI Framework 会有大量 Class。

手动加载很快会变得复杂。

因此需要 Autoload。

最常见的方式是根据 Namespace 自动寻找 Class 文件。

例如:

SAI\Object\ObjectEntity

对应:

app/Object/ObjectEntity.php

一个简单的 Autoloader:

spl_autoload_register(function ($class) {

    $prefix = 'SAI\\';

    if (strpos($class, $prefix) !== 0) {
        return;
    }

    $relative = substr($class, strlen($prefix));

    $file = __DIR__
          . '/app/'
          . str_replace('\\', '/', $relative)
          . '.php';

    if (is_file($file)) {
        require_once $file;
    }
});

于是:

use SAI\Object\ObjectEntity;

$object = new ObjectEntity();

在需要 Class 时自动加载。

运行关系:

new ObjectEntity()
       ↓
Namespace
       ↓
Autoload
       ↓
寻找 PHP 文件
       ↓
require
       ↓
Class Loaded

这样 Framework 就不需要在每个文件里不断写大量 require_once


5.6 配置文件

SAI Framework 的运行参数应该与代码分离。

例如:

config/app.php

可以保存:

<?php

return array(
    'name'    => 'SAI Framework',
    'version' => '0.1.0',
    'debug'   => true
);

读取:

$config = require __DIR__ . '/config/app.php';

echo $config['name'];

可以进一步拆分:

config/
├── app.php
├── individual.php
├── information.php
├── memory.php
├── behavior.php
└── device.php

例如:

return array(
    'name' => 'Individual-001',
    'type' => 'general'
);

配置与代码分离的好处是:

代码
≠
运行参数

修改 Individual 的名称,不需要修改核心 Class。


5.7 Storage

SAI 是持续运行的 Individual,因此不能只有 PHP Class。

运行过程中还会产生:

Memory
State
Experience
Log
Runtime Data

因此需要 Storage。

例如:

storage/
├── memory/
├── experience/
├── state/
├── logs/
└── runtime/

Memory

例如:

storage/memory/

保存:

Fact
Knowledge
History
Memory Data

Experience

storage/experience/

保存:

Experience
Action Result
Historical Pattern

State

storage/state/

保存:

Individual State
Object State
Device State

Logs

storage/logs/

用于:

运行记录
错误记录
异常记录
调试记录

Runtime

storage/runtime/

可以用于:

临时数据
运行缓存
任务状态

需要注意:

Storage 是数据持久化和运行数据管理机制,不等于 Memory 本身。

Memory 是 SAI 的认知组成部分。

Storage 是工程上的数据保存设施。

两者必须区分。


5.8 Extension

SAI Framework 需要允许开发者增加新的能力。

例如核心 Framework:

Core
Information
Cognition
Memory
Reasoning
Decision
Behavior

外部可以增加:

Robot
Drone
Vehicle
Sensor
IndustrialDevice

形成:

SAI Framework
       │
       ├── Core
       │
       └── Extensions
              ├── Robot
              ├── Drone
              └── Vehicle

Extension 可以增加:

Engine
Adapter
Renderer
Object
Device
Template

例如:

class RobotAdapter
{
    public function execute($command)
    {
        // 设备执行
    }
}

核心 Framework 不需要因此修改成机器人专用 Framework。

这就是开放扩展思想。


5.9 开发调试

开发 SAI Framework 时,调试非常重要。

PHP 可以打开错误显示:

error_reporting(E_ALL);
ini_set('display_errors', '1');

开发环境可以使用:

Debug = true

生产环境则应该关闭详细错误输出:

Debug = false

调试时可以检查:

Class 是否加载
Object 是否创建
Information 是否进入
Engine 是否运行
Memory 是否保存
Rule 是否匹配
Decision 是否产生
Behavior 是否执行

例如:

var_dump($individual);

或者记录:

file_put_contents(
    'storage/logs/sai.log',
    date('Y-m-d H:i:s') . " Individual started\n",
    FILE_APPEND
);

随着 Framework 成熟,可以进一步建立统一 Logger。


5.10 错误处理

SAI Framework 是一个长期运行的系统,因此错误处理不能只依赖:

echo error

应该建立统一的异常机制。

例如:

try {

    $individual->run();

} catch (\Exception $e) {

    echo $e->getMessage();
}

Framework 可以进一步定义:

SAIException
├── ConfigurationException
├── ObjectException
├── EngineException
├── MemoryException
├── DeviceException
└── ExtensionException

例如:

class EngineException extends \Exception
{
}

然后:

throw new EngineException(
    'ReasoningEngine failed.'
);

统一错误处理可以让 Central 或 Application 对异常进行协调。

例如:

Exception
 ↓
Central
 ↓
Detection
 ↓
Diagnosis
 ↓
Recovery / Stop
 ↓
Log

这样错误处理可以逐渐与后面的 Self Maintenance 联系起来。


5.11 第一个 SAI 项目

现在建立一个最小的 SAI 项目。

本节只是教程中的最小运行示例设计,下面代码需要实际保存到本地 PHP 环境后才能进行运行验证。

目录:

sai-demo/
│
├── app/
│   └── Individual/
│       └── Individual.php
│
├── config/
│   └── app.php
│
├── bootstrap.php
│
└── index.php

5.11.1 Individual

文件:

app/Individual/Individual.php

代码:

<?php

namespace SAI\Individual;

class Individual
{
    protected $id;
    protected $name;
    protected $state;

    public function __construct($id, $name)
    {
        $this->id = $id;
        $this->name = $name;
        $this->state = 'created';
    }

    public function start()
    {
        $this->state = 'running';
    }

    public function getId()
    {
        return $this->id;
    }

    public function getName()
    {
        return $this->name;
    }

    public function getState()
    {
        return $this->state;
    }
}

这个 Class 目前非常简单。

它只表达:

Individual
├── id
├── name
└── state

以及:

start()

5.11.2 配置文件

文件:

config/app.php

代码:

<?php

return array(
    'name' => 'SAI Framework',
    'version' => '0.1.0',
    'debug' => true
);

5.11.3 Bootstrap

文件:

bootstrap.php

代码:

<?php

error_reporting(E_ALL);
ini_set('display_errors', '1');

spl_autoload_register(function ($class) {

    $prefix = 'SAI\\';

    if (strpos($class, $prefix) !== 0) {
        return;
    }

    $relative = substr($class, strlen($prefix));

    $file = __DIR__
          . '/app/'
          . str_replace('\\', '/', $relative)
          . '.php';

    if (is_file($file)) {
        require_once $file;
    }
});

Bootstrap 当前只负责:

PHP 环境初始化
 ↓
错误设置
 ↓
Autoload

5.11.4 index.php

文件:

index.php

代码:

<?php

require_once __DIR__ . '/bootstrap.php';

$config = require __DIR__ . '/config/app.php';

use SAI\Individual\Individual;

$individual = new Individual(
    'individual_001',
    'SAI Individual'
);

$individual->start();

echo '<pre>';

echo "Framework: "
    . $config['name']
    . PHP_EOL;

echo "Version: "
    . $config['version']
    . PHP_EOL;

echo "Individual ID: "
    . $individual->getId()
    . PHP_EOL;

echo "Individual Name: "
    . $individual->getName()
    . PHP_EOL;

echo "State: "
    . $individual->getState()
    . PHP_EOL;

echo '</pre>';

5.12 本章运行验证

这一节非常重要。

教程代码写出来,不等于项目已经验证成功。

只有实际执行后,才能确认运行结果。

例如在项目目录执行:

php -v

确认 PHP 环境。

然后:

php -l bootstrap.php

检查 Bootstrap 语法。

再检查:

php -l app/Individual/Individual.php

检查 Individual。

最后:

php -l index.php

检查入口文件。

如果使用 PHP CLI,可以运行:

php index.php

预期结构应该类似:

Framework: SAI Framework
Version: 0.1.0
Individual ID: individual_001
Individual Name: SAI Individual
State: running

这里的“预期”只是根据代码推导出的结果。

在没有实际运行环境验证之前,不能把它称为已经验证通过。


本章完整运行关系

第一个 SAI 项目的实际工程关系可以简化为:

index.php
    │
    ↓
bootstrap.php
    │
    ├── Error Configuration
    │
    └── Autoload
    │
    ↓
config/app.php
    │
    ↓
Individual
    │
    ├── id
    ├── name
    └── state
    │
    ↓
start()
    │
    ↓
state = running
    │
    ↓
Output

进一步进入完整 SAI Framework 后:

Bootstrap
    ↓
Application
    ↓
Container
    ↓
Individual
    ↓
Central
    ↓
Information
    ↓
Perception
    ↓
Cognition
    ↓
Memory
    ↓
Reasoning
    ↓
Decision
    ↓
Behavior

也就是说,本章建立的只是开发基础

还没有真正实现完整的:

Perception
Cognition
Memory
Reasoning
Decision
Behavior
Learning

这些内容将在后续章节逐步建立。


本章小结

SAI Framework 的开发环境可以归纳为:

PHP
 ↓
OOP
 ↓
Namespace
 ↓
Autoload
 ↓
Configuration
 ↓
Storage
 ↓
Extension
 ↓
Debug
 ↓
Exception
 ↓
SAI Framework
 ↓
Individual

其中最重要的几个工程原则是:

1. PHP 是实现语言

PHP
 ↓
OOP
 ↓
SAI

但 SAI 的概念不能被限制成 Web。

2. Namespace 建立模块边界

SAI\Information
SAI\Object
SAI\Memory
SAI\Reasoning
SAI\Decision

3. Autoload 管理 Class 加载

Class
 ↓
Namespace
 ↓
Autoload
 ↓
PHP File

4. Configuration 与代码分离

Code
≠
Configuration

5. Storage 与 Memory 分离

Storage
=
工程数据保存

Memory
=
Individual 的记忆机制

6. Extension 保持 Framework 开放

Core
 ↓
Extension
 ↓
Custom Individual

7. 最重要的是运行验证

编写代码
 ↓
语法检查
 ↓
实际运行
 ↓
检查输出
 ↓
确认结果

因此,第5章真正建立的是:

一个可以逐步向 SAI Framework 演进的 PHP OOP 工程基础,而不是把几个 PHP 文件简单组合起来。

下一章进入 第6章 SAI Framework 项目目录结构,将把 Core、Information、Scene、Individual、Central、Cognition、Memory、Reasoning、Decision、Behavior、Template、Renderer、Adapter、Device、Learning、Extension 等目录的职责逐一确定,并形成完整的 Framework 目录体系。

Leave a Reply

Your email address will not be published. Required fields are marked *