phalapi

SKILL开发
开发 未标注权限 许可证不明确
安装这个技能

Use when developing APIs with PhalApi framework in PHP, including creating API interfaces, configuring Domain/Model layers, setting up database connections, debugging PhalApi projects, or working with PhalApi ADM architecture, NotORM, caching, logging, and filters.

一句话选型结论

按资料字段整理

phalapi是开发类的 Agent Skill,安装方式未标注,权限级别未标注,许可证不明确,有可直接复制的安装命令。技能本质是给模型读的说明书,效果取决于模型与客户端;装完先用一个小任务验证,再放进正式流程。

分类开发 安装方式未标注 权限级别未标注权限 许可证许可证不明确
累计安装 未标注 本周 未标注
GitHub 星标 未标注 仓库 未标注
下载量 未标注 技能市场下载数
权限级别 未标注权限 安装前请确认风险范围
许可证 许可证不明确 未说明

安装

未标注
在支持 Skills 的客户端里执行,装完问一句「你有哪些技能」验证
skillhub install user_ef796dd2/phalapi
  1. 1
    确认客户端支持

    确认你的客户端支持 Skills(Claude、Codex、Cursor 等),并升级到较新的版本。

  2. 2
    拿到技能文件

    执行上面的命令安装;也可以把仓库里的 SKILL.md 手动放进客户端的 skills 目录。

  3. 3
    刷新技能列表

    重新打开客户端,或刷新技能列表,让新放进来的技能被加载。

  4. 4
    验证是否生效

    问一句「你有哪些技能」,确认列表里出现它,再拿一个小任务试跑。

技能档案

开发
字段来自技能仓库与公开索引,中文说明由本站标注
作者 / 维护方user_ef796dd2仓库 未标注 · 版本 未标注
宿主客户端未标注技能可被这些客户端加载
安装方式未标注安装包 community
权限级别未标注权限安装前请确认风险范围
许可证未说明许可证不明确,商用前请自行确认条款
仓库可用性available技能仓库当前是否可访问
最近核验未标注上游最后核验时间 · 数据更新 1791623982
正文体量46.2 KBSKILL.md 原文大小,越大说明说明书写得越细

典型使用场景

3 类
按分类整理的常见用法,具体以 SKILL.md 为准
写代码与改 bug

按需求补代码、定位并修掉报错。

读仓库与生成改动

让模型读懂项目结构,再给出可落地的改动。

跑测试与排查故障

按现象排查问题,补测试用例并复跑。

选择建议

装之前先看这几条
按条目字段给出的判断,不替你决定用不用

值得选的地方

  • 有可直接复制的安装命令,不用自己翻文档找入口。

先想清楚的地方

  • 没有标注权限级别,实际能做什么要装好后确认。
  • 许可证不明确,商用或二次分发前先到仓库确认条款。
  • 没有做站内核验,内容以作者仓库为准。
  • 技能只是说明书,实际效果取决于模型与客户端,装完先用小任务试一遍。

更适合

  • 需要在开发场景里给模型补一套做法的人。
  • 愿意先读一遍 SKILL.md、确认它会让模型做什么的人。

不太适合

  • 对许可证要求很严、必须明确可商用的人。
  • 只想装完就自动变强、不打算看说明书的人。

同类对比

6 个同类
同分类里挑最接近的几条,字段以各自详情页为准
技能权限级别安装方式累计安装宿主客户端安装命令
phalapi当前 未标注权限 未标注 未标注 未标注 有
技能审查员 浏览器控制 ClawHub 市场 877.9 万 OpenClaw 有
Vercel React 最佳实践 浏览器控制 GitHub 仓库 849.1 万 Codex、Claude、Cursor 有
GitHub 代码协作 联网访问 ClawHub 市场 763.3 万 OpenClaw 有
网页设计指南 联网访问 GitHub 仓库 668.6 万 Codex、Claude、Cursor 有
本体论 只读 ClawHub 市场 663.7 万 OpenClaw 有

SKILL.md 全文

46.2 KB
模型实际读到的说明书原文,来自技能仓库

PhalApi 开发指南

概述

PhalApi(π框架)是一个 PHP 轻量级开源接口框架,专注于接口服务开发。支持 HTTP/SOAP/RPC 协议,采用 ADM(Api-Domain-Model)分层架构,自动生成在线接口文档。

核心架构:ADM 模式

三层职责

层级 职责 不应该做
Api层 接收请求、参数验证、调度 Domain 层、返回结果 直接操作数据库、业务规则处理
Domain层 业务规则处理、数据逻辑、调用 Model 层 直接数据库操作、实现缓存
Model层 数据库操作、缓存实现 业务规则处理

调用规则

Api层 → Domain层 → Model层

严格禁止:Api 直接调用 Model、Domain 调用 Api、Model 调用 Domain

快速开始

安装

composer create-project phalapi/phalapi

目录结构

./phalapi
├── public/              # 网站根目录
│   ├── index.php       # 入口
│   ├── init.php        # 初始化
│   └── docs.php        # 离线文档生成
├── src/app/            # 源代码
│   ├── Api/            # 接口层
│   ├── Domain/         # 领域层
│   ├── Model/          # 模型层
│   └── Common/         # 公共类
├── config/             # 配置
│   ├── app.php         # 应用配置
│   ├── dbs.php         # 数据库配置
│   ├── di.php          # DI服务
│   └── sys.php         # 系统配置
└── runtime/            # 运行目录(需写权限)

请求示例

http://dev.phalapi.net/?s=App.Site.Index

Api 层开发

创建接口

文件:./src/app/Api/User.php

<?php
namespace App\Api;
use PhalApi\Api;

class User extends Api {

    public function getRules() {
        return array(
            'login' => array(
                'username' => array('name' => 'username', 'require' => true),
                'password' => array('name' => 'password', 'require' => true, 'min' => 6),
            ),
        );
    }

    public function login() {
        $name = $this->username;
        $pass = $this->password;
        return array('username' => $name);
    }
}

接口返回格式

{
    "ret": 200,
    "data": { "key": "value" },
    "msg": ""
}

异常返回

throw new \PhalApi\Exception\BadRequestException('签名失败', 401);
{
    "ret": 401,
    "data": {},
    "msg": "Bad Request: 签名失败"
}

自定义业务异常

// ./src/app/Common/AppException.php
namespace App\Common;
use PhalApi\Exception;

class AppException extends Exception {}

// 抛出
throw new AppException('提示消息', 1000);

JSONP/XML 支持

// config/di.php
$di->response = new \PhalApi\Response\JsonpResponse($_GET['callback']);
$di->response = new \PhalApi\Response\XmlResponse();

参数规则

三级参数规则

  1. 系统参数:service/s 参数(框架保留)
  2. 应用参数:全部接口通用(在 config/app.php 的 apiCommonRules 配置)
  3. 接口参数:特定接口专用

参数类型

类型 配置 说明
string type => 'string' 字符串,默认
int type => 'int' 整数
float type => 'float' 浮点数
boolean type => 'boolean' 布尔值
date type => 'date', 'format' => 'timestamp' 日期/时间戳
array type => 'array', 'format' => 'explode' 数组
enum type => 'enum', 'range' => ['a', 'b'] 枚举
file type => 'file' 文件上传
callable type => 'callable', 'callback' => 'Class::method' 回调验证

完整参数配置

array(
    'name' => 'username',           // 参数名
    'type' => 'string',            // 类型
    'require' => true,            // 是否必须
    'default' => 'PhalApi',       // 默认值
    'min' => 1,                    // 最小值/长度
    'max' => 50,                   // 最大值/长度
    'regex' => '/^[a-z]+$/',      // 正则验证
    'format' => 'utf8',           // 格式(utf8/gbk)
    'source' => 'post',            // 数据来源
    'desc' => '用户名',            // 描述
    'message' => '自定义错误提示',  // 错误提示
)

Domain 层开发

文件:./src/app/Domain/User.php

<?php
namespace App\Domain;
use PhalApi\Domain_Base;

class User extends Domain_Base {

    public function login($name, $pass) {
        $model = new \App\Model\User();
        return $model->getByName($name);
    }
}

Domain 调用规则

  • Domain 可调用 Domain(同级)
  • Domain 可调用 Model
  • Domain 不可调用 Api

Model 层开发

基本 Model

文件:./src/app/Model/User.php

<?php
namespace App\Model;
use PhalApi\Model\NotORMModel as NotORM;

class User extends NotORM {

    protected function getTableName($id) {
        return 'user';  // 自动映射为 tbl_user
    }

    public function getByName($name) {
        return $this->getORM()->where('name', $name)->fetchOne();
    }
}

NotORM 数据库操作

查询

// 获取单条
$this->getORM()->where('id', 1)->fetchOne();

// 获取多条
$this->getORM()->where('id', array(1, 2, 3))->fetchAll();

// 条件
$this->getORM()->where('name LIKE ?', '%test%')->fetchAll();
$this->getORM()->where('age > ?', 18)->order('age DESC')->fetchAll();

// 分页
$this->getORM()->page(1, 20)->fetchAll();  // 第1页,每页20条

// 原生SQL
$this->getORM()->queryAll('SELECT * FROM user WHERE id > ?', [$id]);

插入

$data = array('name' => 'test', 'age' => 20);
$id = $this->getORM()->insert($data);

// 批量插入
$this->getORM()->insert_multi($rows);

// 插入或更新
$this->getORM()->insert_update($unique, $insert, $update);

更新

$this->getORM()->where('id', 1)->update($data);

// 计数器
$this->getORM()->where('id', 1)->updateCounter('age', 1);  // age + 1

删除

$this->getORM()->where('id', 1)->delete();
// 禁止全表删除!

分表

protected function getTableName($id) {
    $tableName = 'log';
    if ($id !== null) {
        $tableName .= '_' . ($id % 100);  // log_0, log_1, ...
    }
    return $tableName;
}

数据库配置

config/dbs.php

return array(
    'servers' => array(
        'db_master' => array(
            'type'     => 'mysql',
            'host'     => '127.0.0.1',
            'name'     => 'phalapi',
            'user'     => 'root',
            'password' => '',
            'port'     => 3306,
            'charset'  => 'UTF8',
        ),
    ),
    'tables' => array(
        '__default__' => array(
            'prefix' => 'tbl_',
            'key' => 'id',
            'map' => array(array('db' => 'db_master')),
        ),
    ),
);

全局获取 NotORM

$user = \PhalApi\DI()->notorm->user->where('id', 1)->fetchOne();

缓存

文件缓存

$di->cache = new \PhalApi\Cache\FileCache(array(
    'path' => API_ROOT . '/runtime',
    'prefix' => 'demo',
));

\PhalApi\DI()->cache->set('key', $value, 600);
\PhalApi\DI()->cache->get('key');
\PhalApi\DI()->cache->delete('key');

Redis 缓存

$di->cache = new \PhalApi\Cache\RedisCache(array(
    'host' => '127.0.0.1',
    'port' => 6379,
));

Memcache 缓存

$di->cache = new \PhalApi\Cache\MemcachedCache(array(
    'host' => '127.0.0.1',
    'port' => 11211,
));

日志

三种日志级别

\PhalApi\DI()->logger->error('错误描述', $context);
\PhalApi\DI()->logger->info('业务记录', $context);
\PhalApi\DI()->logger->debug('调试信息', $context);

文件日志配置

$di->logger = new \PhalApi\Logger\FileLogger(
    API_ROOT . '/runtime',
    \PhalApi\Logger::LOG_LEVEL_DEBUG | \PhalApi\Logger::LOG_LEVEL_INFO | \PhalApi\Logger::LOG_LEVEL_ERROR
);

过滤器(签名验证)

启用 MD5 签名

// config/di.php
$di->filter = new \PhalApi\Filter\SimpleMD5Filter();

白名单配置

// config/app.php
'service_whitelist' => array(
    'Site.Index',    // 精确匹配
    '*.List',        // 通配符匹配
),

自定义过滤器

// ./src/app/Common/SignFilter.php
namespace App\Common;
use PhalApi\Filter;
use PhalApi\Exception\BadRequestException;

class SignFilter implements Filter {
    public function check() {
        $signature = \PhalApi\DI()->request->get('signature');
        // 验签逻辑
        if ($signature !== $expected) {
            throw new BadRequestException('wrong sign', 402);
        }
    }
}

// config/di.php
$di->filter = new \App\Common\SignFilter();

DI 服务

config/di.php

$di = \PhalApi\DI();

// 配置
$di->config = new \PhalApi\Config\FileConfig(API_ROOT . '/config');

// 数据库
$di->notorm = new \PhalApi\Database\NotORMDatabase($di->config->get('dbs'));

// 缓存
$di->cache = new \PhalApi\Cache\RedisCache([...]);

// 日志
$di->logger = new \PhalApi\Logger\FileLogger([...]);

// 签名
$di->filter = new \PhalApi\Filter\SimpleMD5Filter();

常用 DI 服务

服务 说明
$di->config 配置读取
$di->request 请求参数
$di->response 响应输出
$di->notorm 数据库
$di->cache 缓存
$di->logger 日志
$di->filter 过滤器

配置读取

\PhalApi\DI()->config->get('app');           // 全部配置
\PhalApi\DI()->config->get('app.version');    // 单个配置
\PhalApi\DI()->config->get('app.not_found', 'default');  // 默认值

环境配置

defined('API_MODE') || define('API_MODE', 'prod');
// dev: 加载 *_dev.php
// test: 加载 *_test.php
// prod: 加载 *.php

初始化

public/init.php

defined('API_ROOT') || define('API_ROOT', dirname(__FILE__) . '/..');
defined('API_MODE') || define('API_MODE', 'prod');
require_once API_ROOT . '/vendor/autoload.php';
date_default_timezone_set('Asia/Shanghai');
include API_ROOT . '/config/di.php';
\PhalApi\SL('zh_cn');

自动加载(PSR-4)

命名空间对应

命名空间 文件路径
App\Api\User src/app/Api/User.php
App\Domain\User src/app/Domain/User.php
App\Model\User src/app/Model/User.php

使用类

use App\Domain\User as DomainUser;
$domain = new DomainUser();

// 或完整路径
$domain = new \App\Domain\User();

添加全局函数

// src/app/functions.php
namespace App;
function hello() { return 'world'; }

// 使用
\App\hello();

在线接口文档

访问地址

  • 列表:http://dev.phalapi.net/docs.php
  • 详情:http://dev.phalapi.net/docs.php?service=App.Site.Index&detail=1

注释规范

/**
 * 用户登录
 * @desc 用于用户登录验证
 * @return int user_id 用户ID
 * @return string token 登录令牌
 * @exception 400 参数错误
 * @exception 401 签名错误
 */
public function login() { }

// 隐藏接口
/**
 * @ignore
 */
public function hidden() { }

生成离线文档

php ./public/docs.php expand  # 展开版
php ./public/docs.php fold    # 折叠版

单元测试

自动生成测试

php ./bin/phalapi-buildtest ./src/app/Api/User.php App\\Api\\User > ./tests/app/Api/User_Test.php

测试示例

class PhpUnderControl_AppApiUser_Test extends \PHPUnit_Framework_TestCase
{
    public function testLogin() {
        // 构造
        $url = 's=User.Login';
        $params = array('username' => 'test', 'password' => '123456');

        // 操作
        $rs = \PhalApi\Helper\TestRunner::go($url, $params);

        // 检验
        $this->assertEquals(0, $rs['code']);
    }
}

CURL 请求

$curl = new \PhalApi\CUrl();

// GET
$rs = $curl->get('http://api.example.com/?id=1', 3000);

// POST
$rs = $curl->post('http://api.example.com/', array('name' => 'test'), 3000);

扩展类库

常用扩展(通过 composer 安装):

{
    "require": {
        "phalapi/redis": "2.*",
        "phalapi/jwt": "2.*",
        "phalapi/pay": "2.*"
    }
}

请求数据来源

// 全局指定
$di->request = new \PhalApi\Request($_POST);

// 参数级别
'source' => 'get'   // $_GET
'source' => 'post'  // $_POST
'source' => 'header' // $_SERVER['HTTP_X']

事务操作

// 方式1:全局
\PhalApi\DI()->notorm->beginTransaction('db_master');
\PhalApi\DI()->notorm->user->insert($data);
\PhalApi\DI()->notorm->commit('db_master');

// 方式2:局部
$this->getORM()->transaction('BEGIN');
$this->getORM()->transaction('COMMIT');
$this->getORM()->transaction('ROLLBACK');

NotORM 数据库操作详解

SELECT 查询

// 基础查询
$this->getORM()->select('id, name')->fetchAll();
$this->getORM()->select('DISTINCT name')->fetchAll();
$this->getORM()->select('id, name, MAX(age) AS max_age')->fetchAll();

// 指定字段
$this->getORM()->select('id, name, email')->where('status', 1)->fetchAll();

WHERE 条件

// 等值条件
$this->getORM()->where('id', 1)->fetchOne();
$this->getORM()->where('id = ?', 1)->fetchOne();

// 多条件 AND(链式调用)
$this->getORM()->where('status', 1)->where('age > ?', 18)->fetchAll();

// OR 条件
$this->getORM()->where('status = ? OR type = ?', 1, 2)->fetchAll();
$this->getORM()->where('status', 1)->or('type', 2)->fetchAll();

// 嵌套条件
$this->getORM()->where('(name = ? OR id = ?)', 'test', 1)->fetchAll();

// IN 查询
$this->getORM()->where('id', array(1, 2, 3))->fetchAll();

// NOT IN
$this->getORM()->where('NOT id', array(1, 2, 3))->fetchAll();

// 模糊匹配
$this->getORM()->where('name LIKE ?', '%test%')->fetchAll();

// NULL 判断
$this->getORM()->where('name IS NULL')->fetchAll();
$this->getORM()->where('name IS NOT NULL')->fetchAll();

ORDER 排序

// 单字段排序
$this->getORM()->order('age DESC')->fetchAll();

// 多字段排序
$this->getORM()->order('id, age DESC')->fetchAll();

LIMIT 和分页

// 限制条数
$this->getORM()->limit(10)->fetchAll();

// 偏移量(跳过5条,取10条)
$this->getORM()->limit(10, 5)->fetchAll();

// 分页(2.8.0+),第2页每页10条
$this->getORM()->page(2, 10)->fetchAll();

GROUP BY 和 HAVING

// 分组统计
$this->getORM()->select('note, COUNT(*) AS count')->group('note')->fetchAll();

// 分组 + HAVING
$this->getORM()->select('note, COUNT(*) AS count')->group('note', 'age > 10')->fetchAll();

获取结果的不同方式

// fetch() - 循环获取单条
$row = $this->getORM()->where('status', 1)->fetch();

// fetchOne() / fetchRow() - 获取单条(推荐)
$row = $this->getORM()->where('id', 1)->fetchOne();

// fetchAll() / fetchRows() - 获取全部
$rows = $this->getORM()->where('status', 1)->fetchAll();

// fetchPairs() - 获取键值对
$pairs = $this->getORM()->fetchPairs('id', 'name');
// 结果:array(1 => '张三', 2 => '李四')

// queryAll() / queryRows() - 原生SQL查询
$rows = $this->getORM()->queryAll('SELECT * FROM user WHERE id > ?', array($id));

聚合函数

// 计数
$count = $this->getORM()->where('status', 1)->count();

// 最小值
$min = $this->getORM()->min('age');

// 最大值
$max = $this->getORM()->max('age');

// 求和
$sum = $this->getORM()->sum('score');

// 综合使用
$this->getORM()->select('COUNT(*) AS total, MAX(age) AS max_age, SUM(score) AS total_score')
    ->where('status', 1)->fetchOne();

插入数据

// 单条插入
$id = $this->getORM()->insert(array(
    'name' => '张三',
    'email' => 'zhangsan@example.com',
    'created_at' => time(),
));

// 获取自增ID
$id = $this->getORM()->insert_id();

// 批量插入
$rows = array(
    array('name' => '张三', 'email' => 'zhangsan@example.com'),
    array('name' => '李四', 'email' => 'lisi@example.com'),
);
$this->getORM()->insert_multi($rows);

// 插入或更新(有则更新,无则插入)
$this->getORM()->insert_update(
    array('name' => '张三'),                    // 唯一键条件
    array('name' => '张三', 'age' => 25),       // 插入数据
    array('age' => 26)                          // 更新数据(已存在时)
);

更新数据

// 条件更新
$affected = $this->getORM()->where('id', 1)->update(array(
    'name' => '新名字',
    'updated_at' => time(),
));

// 返回值说明:
// int(1) - 更新成功
// int(0) - 数据无变化
// false  - 更新失败

// 计数器更新(2.6.0+)- age + 1
$this->getORM()->where('id', 1)->updateCounter('age', 1);

// 计数器递减 - age - 1
$this->getORM()->where('id', 1)->updateCounter('age', -1);

// 多计数器同时更新(2.6.0+)
$this->getORM()->where('id', 1)->updateMultiCounters(array(
    'age' => 1,
    'points' => 10,
));

删除数据

// 条件删除
$affected = $this->getORM()->where('id', 1)->delete();

// 禁止全表删除!以下写法会报错
// $this->getORM()->delete();

// 批量删除
$this->getORM()->where('id', array(1, 2, 3))->delete();

// 条件删除
$this->getORM()->where('status = ? AND created_at < ?', 0, time() - 86400)->delete();

原生 SQL

// queryAll - 查询类SQL,返回结果集
$rows = $this->getORM()->queryAll('SELECT * FROM user WHERE id > ?', array($id));

// executeSql - 写入类SQL(2.6.0+),返回影响行数
$affected = $this->getORM()->executeSql('UPDATE user SET status = ? WHERE id = ?', array(0, 1));

// query - 最底层的查询方法
$result = $this->getORM()->query('SELECT * FROM user WHERE id = ?', array($id));

事务操作详解

方式一:全局事务

\PhalApi\DI()->notorm->beginTransaction('db_master');

try {
    \PhalApi\DI()->notorm->user->insert(array('name' => 'test'));
    \PhalApi\DI()->notorm->order->insert(array('user_id' => 1));
    \PhalApi\DI()->notorm->commit('db_master');
} catch (\Exception $e) {
    \PhalApi\DI()->notorm->rollback('db_master');
    throw $e;
}

方式二:局部事务

$this->getORM()->transaction('BEGIN');

try {
    $this->getORM()->insert(array('name' => 'test'));
    $this->getORM()->where('id', 1)->update(array('status' => 1));
    $this->getORM()->transaction('COMMIT');
} catch (\Exception $e) {
    $this->getORM()->transaction('ROLLBACK');
    throw $e;
}

事务注意事项

  • NotORM 实例带状态,事务中每次操作前需获取新实例
  • 局部事务使用 $this->getORM() 获取新实例
  • 全局事务指定数据库名称(如 'db_master')

关联查询

左连接查询(2.12.0+ 推荐)

$rows = $this->getORM()
    ->alias('u')                                    // 主表别名
    ->select('u.id, u.name, p.avatar')              // 选择字段
    ->leftJoin('profile', 'p', 'u.id = p.user_id')  // 左连接
    ->where('u.status', 1)
    ->order('u.id DESC')
    ->fetchAll();

NotORM 自动关联(点号表示法)

// 前提:表间有外键关联
$this->getORM()->select('user.username, comment.content')->fetchAll();

分库分表

分表配置

在 config/dbs.php 的 tables 中配置分表策略:

'tables' => array(
    '__default__' => array(
        'prefix' => 'tbl_',
        'key' => 'id',
        'map' => array(
            array('db' => 'db_master'),
        ),
    ),
    // 分表示例:log 表分成3个表
    'log' => array(
        'prefix' => 'tbl_',
        'key' => 'id',
        'map' => array(
            array('db' => 'db_master', 'start' => 0, 'end' => 2),
            // 对应 tbl_log_0, tbl_log_1, tbl_log_2
        ),
    ),
),

Model 中实现分表

class Log extends NotORM {

    protected function getTableName($id) {
        $tableName = 'log';
        if ($id !== null) {
            $tableName .= '_' . ($id % 100);  // log_0, log_1, ..., log_99
        }
        return $tableName;
    }

    // 使用时传入 $id 获取分表实例
    public function getByLogId($id) {
        return $this->getORM($id)->where('id', $id)->fetchOne();
    }
}

分库配置

'servers' => array(
    'db_master' => array(         // 主数据库
        'type' => 'mysql',
        'host' => '192.168.1.100',
        'name' => 'phalapi_main',
        'user' => 'root',
        'password' => '',
        'port' => 3306,
        'charset' => 'UTF8',
    ),
    'db_ext' => array(            // 扩展数据库
        'type' => 'mysql',
        'host' => '192.168.1.200',
        'name' => 'phalapi_ext',
        'user' => 'root',
        'password' => '',
        'port' => 3306,
        'charset' => 'UTF8',
    ),
),

'tables' => array(
    '__default__' => array(
        'prefix' => 'tbl_',
        'key' => 'id',
        'map' => array(
            array('db' => 'db_master'),
        ),
    ),
    'order' => array(            // order 表使用扩展库
        'prefix' => 'tbl_',
        'key' => 'id',
        'map' => array(
            array('db' => 'db_ext'),
        ),
    ),
),

自动建表

php ./bin/phalapi-buildsqls

keep_suffix_if_no_map(2.12.0+)

当表名保留下划线+数字后缀时:

'tables' => array(
    'log' => array(
        'prefix' => 'tbl_',
        'key' => 'id',
        'keep_suffix_if_no_map' => true,  // 保留后缀
        'map' => array(
            array('db' => 'db_master'),
        ),
    ),
),

多数据库连接

简单方案:同一配置文件

在 config/dbs.php 中配置多个 servers,通过 tables 的 map 路由到不同数据库。

复杂方案:独立配置和 NotORM 实例

步骤 1:创建配置文件 config/dbs_ms.php

return array(
    'servers' => array(
        'db_ms' => array(
            'type'     => 'sqlserver',  // dblib_sqlserver
            'host'     => '192.168.1.100',
            'name'     => 'phalapi_ms',
            'user'     => 'sa',
            'password' => '',
            'port'     => 1433,
            'charset'  => 'UTF8',
        ),
    ),
    'tables' => array(
        '__default__' => array(
            'prefix' => '',
            'key' => 'id',
            'map' => array(
                array('db' => 'db_ms'),
            ),
        ),
    ),
);

步骤 2:创建 Model 基类

// ./src/app/Common/MSModelBase.php
namespace App\Common;
use PhalApi\Model\NotORMModel as NotORM;

class MSModelBase extends NotORM {

    protected function getNotORM() {
        return \PhalApi\DI()->notorm_ms;
    }
}

步骤 3:在 config/di.php 中注册

// 注册 SQL Server 的 NotORM 实例
$di->notorm_ms = new \PhalApi\Database\NotORMDatabase(
    $di->config->get('dbs_ms')
);

步骤 4:Model 继承 MSModelBase

namespace App\Model;
use App\Common\MSModelBase;

class MSUser extends MSModelBase {

    protected function getTableName($id) {
        return 'ms_user';
    }
}

支持的数据库类型

类型 type 配置 说明
MySQL mysql 默认,最常用
SQL Server sqlserver / dblib_sqlserver 需安装 dblib 扩展
PostgreSQL pgsql 需安装 pgsql 扩展

2.8.0+ 切换数据库实例

class ExtModel extends NotORM {

    protected function getNotORM() {
        // 重写此方法切换到其他数据库实例
        return \PhalApi\DI()->notorm_ext;
    }
}

SQL 调试

三个调试开关

配置项 位置 说明
sys.debug config/sys.php 接口调试模式
sys.notorm_debug config/sys.php NotORM 调试模式
sys.enable_sql_log config/sys.php SQL 日志记录
// config/sys.php
return array(
    'debug' => true,            // 开启接口调试
    'notorm_debug' => true,     // 开启 NotORM 调试
    'enable_sql_log' => true,   // 开启 SQL 日志
);

查看执行的 SQL

开启 sys.debug 后,返回结果中会包含 debug.sqls 字段,列出所有执行的 SQL 语句。

日志记录 SQL

开启 sys.enable_sql_log 后,SQL 语句会写入日志文件:

# 实时查看 SQL 日志
tail -f ./runtime/log/20240101.log

自定义 SQL 追踪器

// ./src/app/Common/SqlTracer.php
namespace App\Common;
use PhalApi\Helper\Tracer;

class SqlTracer extends Tracer {

    public function sql($sql, $params = array()) {
        // 自定义追踪逻辑
        \PhalApi\DI()->logger->info('SQL: ' . $sql, $params);
    }
}

// 注册
$di->tracer = new \App\Common\SqlTracer();

缓存详解

FileCache 文件缓存

// config/di.php
$di->cache = new \PhalApi\Cache\FileCache(array(
    'path' => API_ROOT . '/runtime',
    'prefix' => 'demo',
));

// 使用
\PhalApi\DI()->cache->set('key', $value, 600);    // 设置缓存(600秒=10分钟)
$value = \PhalApi\DI()->cache->get('key');          // 获取缓存
\PhalApi\DI()->cache->delete('key');                // 删除缓存

APCUCache APCu 缓存

// config/di.php
$di->cache = new \PhalApi\Cache\APCUCache();

// 使用(接口同上)
\PhalApi\DI()->cache->set('key', $value, 600);
$value = \PhalApi\DI()->cache->get('key');
\PhalApi\DI()->cache->delete('key');

MemcachedCache 缓存

// config/di.php
$di->cache = new \PhalApi\Cache\MemcachedCache(array(
    'host' => '127.0.0.1',
    'port' => 11211,
));

// 多实例配置(用逗号分隔)
$di->cache = new \PhalApi\Cache\MemcachedCache(array(
    'host' => '192.168.1.1,192.168.1.2',  // 多台Memcached
    'port' => '11211,11211',
));

RedisCache 缓存

// config/di.php
$di->cache = new \PhalApi\Cache\RedisCache(array(
    'type'    => 'redis',
    'host'    => '127.0.0.1',
    'port'    => 6379,
    'timeout' => 300,
    'prefix'  => 'phalapi_',
    'auth'    => 'your_password',
    'db'      => 0,
));

// Socket 方式连接
$di->cache = new \PhalApi\Cache\RedisCache(array(
    'type'   => 'unix',
    'socket' => '/var/run/redis/redis.sock',
));

缓存架构对比

驱动 适用场景 优点 缺点
FileCache 开发环境、小数据量 无需额外服务 性能低
APCUCache 单机、高速缓存 极快 不跨进程共享
MemcachedCache 多进程共享、中等数据量 分布式、成熟 无持久化
RedisCache 高性能、大数据量、分布式 持久化、丰富数据结构 需维护 Redis

缓存使用模式

// Domain 层中的缓存使用模式
class User {

    public function getUserInfo($userId) {
        $key = 'user_info_' . $userId;

        // 先查缓存
        $data = \PhalApi\DI()->cache->get($key);
        if ($data !== null) {
            return $data;
        }

        // 缓存未命中,查询数据库
        $model = new \App\Model\User();
        $data = $model->get($userId);

        if (!empty($data)) {
            // 写入缓存,1小时过期
            \PhalApi\DI()->cache->set($key, $data, 3600);
        }

        return $data;
    }
}

日志详解

三种日志级别

方法 用途 示例场景
error() 系统异常 数据库连接失败、外部服务异常
info() 业务记录 用户登录、订单创建
debug() 开发调试 变量值、执行流程
\PhalApi\DI()->logger->error('数据库连接失败', array('host' => $host));
\PhalApi\DI()->logger->info('用户登录', array('user_id' => $userId, 'ip' => $ip));
\PhalApi\DI()->logger->debug('查询参数', array('where' => $where, 'bind' => $bind));

自定义日志类型

// 使用 log() 方法记录自定义类型
\PhalApi\DI()->logger->log('access', '接口访问', array('url' => $url, 'time' => time()));

FileLogger 配置

// 方式一:直接创建
$di->logger = new \PhalApi\Logger\FileLogger(
    API_ROOT . '/runtime',
    \PhalApi\Logger::LOG_LEVEL_DEBUG | \PhalApi\Logger::LOG_LEVEL_INFO | \PhalApi\Logger::LOG_LEVEL_ERROR
);

// 方式二:使用 create 工厂方法(2.7.0+)
$di->logger = \PhalApi\Logger\FileLogger::create(array(
    'log_path' => API_ROOT . '/runtime',
    'log_level' => \PhalApi\Logger::LOG_LEVEL_DEBUG | \PhalApi\Logger::LOG_LEVEL_INFO | \PhalApi\Logger::LOG_LEVEL_ERROR,
));

// 方式三:配置文件 + 工厂方法
// config/sys.php
return array(
    'log_path' => API_ROOT . '/runtime',
    'log_level' => \PhalApi\Logger::LOG_LEVEL_DEBUG | \PhalApi\Logger::LOG_LEVEL_INFO | \PhalApi\Logger::LOG_LEVEL_ERROR,
);

// config/di.php
$di->logger = \PhalApi\Logger\FileLogger::create($di->config->get('sys'));

多日志服务

当不同业务模块需要独立的日志文件时:

// config/sys.php
return array(
    'log_path' => API_ROOT . '/runtime',
    'log_level' => \PhalApi\Logger::LOG_LEVEL_ALL,
    'file_logger_app' => array(
        'log_path' => API_ROOT . '/runtime/app',
        'log_level' => \PhalApi\Logger::LOG_LEVEL_INFO,
    ),
    'file_logger_pay' => array(
        'log_path' => API_ROOT . '/runtime/pay',
        'log_level' => \PhalApi\Logger::LOG_LEVEL_ALL,
    ),
);

// config/di.php
$di->logger_app = \PhalApi\Logger\FileLogger::create($di->config->get('sys.file_logger_app'));
$di->logger_pay = \PhalApi\Logger\FileLogger::create($di->config->get('sys.file_logger_pay'));

// 使用
\PhalApi\DI()->logger_app->info('应用日志', $data);
\PhalApi\DI()->logger_pay->error('支付错误', $errorData);

日志最佳实践

  1. 敏感信息脱敏:日志中避免记录密码、Token 等敏感信息
  2. 合理选择级别:调试信息用 DEBUG,生产环境用 INFO
  3. 结构化日志:使用数组记录上下文信息,便于分析
  4. 日志切割:FileLogger 自动按天分割,避免单个文件过大
  5. 异常必记:所有 catch 块中必须记录异常信息

过滤器(签名验证)

SimpleMD5Filter 签名机制

签名计算规则:

  1. 排除 sign 参数
  2. 将剩余参数按字典序排列
  3. 拼接为 key1=value1&key2=value2&... 格式
  4. 末尾追加密钥
  5. 计算 MD5 值
// 启用 MD5 签名验证
// config/di.php
$di->filter = new \PhalApi\Filter\SimpleMD5Filter();

白名单配置

免签名验证的接口列表:

// config/app.php
'service_whitelist' => array(
    'Site.Index',         // 精确匹配
    'User.GetBaseInfo',   // 精确匹配
    '*.List',             // 通配符匹配(所有 List 结尾的接口)
    'Site.*',             // 通配符匹配(Site 下所有接口)
),

自定义过滤器

// ./src/app/Common/SignFilter.php
namespace App\Common;
use PhalApi\Filter;
use PhalApi\Exception\BadRequestException;

class SignFilter implements Filter {

    public function check() {
        $signature = \PhalApi\DI()->request->get('signature');
        $timestamp = \PhalApi\DI()->request->get('timestamp');

        // 验证时间戳(5分钟内有效)
        if (abs(time() - $timestamp) > 300) {
            throw new BadRequestException('请求过期', 401);
        }

        // 验证签名
        $params = \PhalApi\DI()->request->getAll();
        unset($params['signature']);
        ksort($params);
        $signStr = http_build_query($params) . '&key=your_secret_key';
        $expectedSign = md5($signStr);

        if ($signature !== $expectedSign) {
            throw new BadRequestException('签名验证失败', 402);
        }
    }
}

// config/di.php
$di->filter = new \App\Common\SignFilter();

DataApi 通用数据接口(2.13.0+)

DataApi 提供5个通用数据操作接口,无需为每张表编写单独的接口。

5个内置接口

接口名 功能 说明
CreateData 创建数据 新增记录
DeleteDataIDs 删除数据 根据ID批量删除
GetData 获取数据 单条/多条查询
TableList 表列表 分页查询表数据
UpdateData 更新数据 根据ID更新

使用步骤

步骤 1:创建 Api 类继承 DataApi

// ./src/app/Api/UserData.php
namespace App\Api;
use PhalApi\DataApi;

class UserData extends DataApi {

    protected function userCheck() {
        // 权限验证(必须重写)
        // 返回 true 或抛出异常
        $token = \PhalApi\DI()->request->get('token');
        if (empty($token)) {
            throw new \PhalApi\Exception\BadRequestException('缺少token');
        }
        return true;
    }

    protected function getDataModel() {
        // 返回对应的 Model 实例(必须重写)
        return new \App\Model\UserDataModel();
    }
}

步骤 2:创建 Model 继承 DataModel

// ./src/app/Model/UserDataModel.php
namespace App\Model;
use PhalApi\Model\DataModel;

class UserDataModel extends DataModel {

    protected function getTableName($id) {
        return 'user';
    }
}

DataApi 定制选项

class UserData extends DataApi {

    // 定制表列表查询
    protected function getTableListSelect() { return 'id, name, email'; }
    protected function getTableListOrder() { return 'id DESC'; }
    protected function getTableListWhere() { return array('status' => 1); }

    // 定制创建数据
    protected function createDataRequireKeys() { return array('name', 'email'); }
    protected function createDataExcludeKeys() { return array('id', 'created_at'); }

    // 定制更新数据
    protected function updateDataExcludeKeys() { return array('created_at'); }
}

DataApi 请求示例

# 获取表列表(分页)
GET /?s=App.UserData.TableList&page=1&per_page=20

# 获取单条数据
GET /?s=App.UserData.GetData&id=1

# 创建数据
POST /?s=App.UserData.CreateData
name=张三&email=zhangsan@example.com

# 更新数据
POST /?s=App.UserData.UpdateData&id=1&name=新名字

# 删除数据
POST /?s=App.UserData.DeleteDataIDs&ids=1,2,3

Cookie 操作

基本使用

// 设置 Cookie
\PhalApi\Cookie\FCookie::set('key', 'value', 3600);

// 获取 Cookie
$value = \PhalApi\Cookie\FCookie::get('key');

// 删除 Cookie
\PhalApi\Cookie\FCookie::delete('key');

MultiCookie 加密版

// config/di.php
$di->cookie = new \PhalApi\Cookie\MultiCookie(array(
    'crypt' => new \PhalApi\Crypt\McryptCrypt('your_secret_key'),
    'path' => '/',
    'domain' => '.example.com',
));

// 使用
\PhalApi\DI()->cookie->set('user_token', $token, 86400);
$token = \PhalApi\DI()->cookie->get('user_token');
\PhalApi\DI()->cookie->delete('user_token');

加密和解密

McryptCrypt(对称加密)

use PhalApi\Crypt\McryptCrypt;

$crypt = new McryptCrypt('your_secret_key');

// 加密
$encrypted = $crypt->encrypt('敏感数据', 'secret_key');

// 解密
$decrypted = $crypt->decrypt($encrypted, 'secret_key');

MultiMcryptCrypt(序列化+base64+mcrypt)

use PhalApi\Crypt\MultiMcryptCrypt;

$crypt = new MultiMcryptCrypt('your_secret_key');

// 加密(自动序列化+base64)
$encrypted = $crypt->encrypt(array('user_id' => 1, 'role' => 'admin'), 'secret_key');

// 解密(自动反序列化)
$data = $crypt->decrypt($encrypted, 'secret_key');

RSA 非对称加密

use PhalApi\Crypt\Rsa\MultiPri2PubCrypt;

// 私钥加密,公钥解密
$rsa = new MultiPri2PubCrypt();

// 加密(使用私钥)
$encrypted = $rsa->encrypt($data, $privateKey);

// 解密(使用公钥)
$decrypted = $rsa->decrypt($encrypted, $publicKey);

Crypt 接口

所有加密类实现 PhalApi\Crypt 接口:

interface Crypt {
    public function encrypt($data, $key);
    public function decrypt($data, $key);
}

HTTP 请求(CUrl)

$curl = new \PhalApi\CUrl();

// GET 请求
$rs = $curl->get('http://api.example.com/?id=1', 3000);  // 3秒超时

// POST 请求
$rs = $curl->post('http://api.example.com/', array('name' => 'test'), 3000);

// 构造参数为重试次数
$curl = new \PhalApi\CUrl(3);  // 失败后最多重试3次
$rs = $curl->get('http://api.example.com/?id=1', 3000);

Tool 工具类

use PhalApi\Tool;

// 获取客户端IP
$ip = Tool::getClientIp();

// 生成随机字符串
$str = Tool::createRandStr(16);              // 默认字母数字
$str = Tool::createRandStr(6, '0123456789'); // 纯数字验证码

// 数组转XML
$xml = Tool::arrayToXml($data);

// XML转数组
$data = Tool::xmlToArray($xml);

// 排除数组中的指定键
$result = Tool::arrayExcludeKeys($data, 'password,token');

扩展类库

安装扩展

// composer.json
{
    "require": {
        "phalapi/redis": "2.*",
        "phalapi/jwt": "2.*",
        "phalapi/pay": "2.*",
        "phalapi/qrcode": "2.*",
        "phalapi/wechat": "2.*",
        "phalapi/sms": "2.*",
        "phalapi/upload": "2.*"
    }
}
composer update

扩展配置和使用

每个扩展需要三步:安装 → 配置 → 注册

// 步骤1:安装(composer require)

// 步骤2:配置(config/app.php 中添加扩展配置)
return array(
    'redis' => array(
        'host' => '127.0.0.1',
        'port' => 6379,
        'auth' => '',
    ),
);

// 步骤3:注册(config/di.php)
$di->redis = new \PhalApi\Redis\Redis($di->config->get('app.redis'));

开发自定义扩展

扩展目录结构:

phalapi-custom-ext/
├── composer.json        # 包信息
├── src/
│   └── Ext.php         # 扩展类
└── README.md
// composer.json
{
    "name": "yourname/phalapi-custom-ext",
    "type": "phalapi-extension",
    "require": {
        "phalapi/kernal": "2.*"
    },
    "autoload": {
        "psr-4": {
            "YourName\\CustomExt\\": "src/"
        }
    }
}

消息队列(Gearman)

Api 层写入队列

// ./src/app/Api/Task.php
namespace App\Api;
use PhalApi\Api;

class Task extends Api {

    public function createTask() {
        $client = new \GearmanClient();
        $client->addServer('127.0.0.1', 4730);

        $data = array(
            'task_id' => $this->taskId,
            'params' => $this->taskParams,
        );

        $client->doBackground('process_task', json_encode($data));

        return array('task_id' => $this->taskId);
    }
}

消费脚本

// ./bin/worker.php
$worker = new \GearmanWorker();
$worker->addServer('127.0.0.1', 4730);

$worker->addFunction('process_task', function($job) {
    $data = json_decode($job->workload(), true);
    // 处理任务逻辑
    $domain = new \App\Domain\Task();
    $domain->process($data);
});

while ($worker->work()) {}

守护进程运行

# 启动 worker
nohup php ./bin/worker.php > /dev/null 2>&1 &

# 查看运行状态
ps aux | grep worker

# 停止
kill -9 $(pgrep -f worker.php)

配置详解

配置读取

// 获取完整配置
$config = \PhalApi\DI()->config->get('app');

// 获取单个配置(多级用点号分隔)
$version = \PhalApi\DI()->config->get('app.version');

// 获取配置(带默认值)
$name = \PhalApi\DI()->config->get('app.name', '默认名称');

环境配置

根据 API_MODE 自动加载不同环境配置:

API_MODE 加载规则 示例
prod app.php 生产配置
dev app_dev.php(优先),app.php(回退) 开发配置
test app_test.php(优先),app.php(回退) 测试配置
// 定义环境模式
defined('API_MODE') || define('API_MODE', 'dev');

Yaconf 扩展支持

// 使用 Yaconf 读取配置(高性能)
$di->config = new \PhalApi\Config\YaconfConfig('phalapi.');

DI 服务详解

服务注册

$di = \PhalApi\DI();

// 配置(必须手动注册)
$di->config = new \PhalApi\Config\FileConfig(API_ROOT . '/config');

// 数据库(推荐注册)
$di->notorm = new \PhalApi\Database\NotORMDatabase($di->config->get('dbs'));

// 日志(必须手动注册)
$di->logger = new \PhalApi\Logger\FileLogger(
    API_ROOT . '/runtime',
    \PhalApi\Logger::LOG_LEVEL_DEBUG | \PhalApi\Logger::LOG_LEVEL_INFO | \PhalApi\Logger::LOG_LEVEL_ERROR
);

// 缓存(推荐注册)
$di->cache = new \PhalApi\Cache\RedisCache(array('host' => '127.0.0.1'));

// 过滤器(推荐注册)
$di->filter = new \PhalApi\Filter\SimpleMD5Filter();

自动注册的服务

服务 说明
$di->request 请求对象(自动注册)
$di->response 响应对象(自动注册)

判断服务是否注册

// 错误方式(未注册时报错)
if (isset($di->cache)) { ... }

// 正确方式(先获取再判断)
$cache = $di->cache;
if (isset($cache)) {
    $cache->get('key');
}

常用 DI 服务一览

服务 是否必须注册 说明
$di->config 必须 配置读取
$di->logger 必须 日志记录
$di->notorm 推荐 数据库操作
$di->cache 推荐 缓存
$di->filter 推荐 签名验证
$di->request 自动 请求参数
$di->response 自动 响应输出

在线接口文档

访问地址

  • 列表:http://dev.phalapi.net/docs.php
  • 详情:http://dev.phalapi.net/docs.php?service=App.Site.Index&detail=1

注释规范

/**
 * 用户登录
 *
 * @desc 用于用户登录验证,返回用户信息和Token
 * @param string username 用户名(必填)
 * @param string password 密码(必填,最少6位)
 * @return int user_id 用户ID
 * @return string token 登录令牌
 * @return string username 用户名
 * @exception 400 参数错误
 * @exception 401 签名错误
 * @exception 403 权限不足
 */
public function login() { }

/**
 * 内部接口(不在文档中显示)
 *
 * @ignore
 */
public function internalMethod() { }

生成离线文档

# 展开版(所有接口详情展开显示)
php ./public/docs.php expand

# 折叠版(接口列表折叠显示)
php ./public/docs.php fold

自动加载(PSR-4)

命名空间对应

命名空间 文件路径
App\Api\User src/app/Api/User.php
App\Domain\User src/app/Domain/User.php
App\Model\User src/app/Model/User.php
App\Common\Utils src/app/Common/Utils.php

多层子命名空间

// App\Api\Weixin\User → src/app/Api/Weixin/User.php
namespace App\Api\Weixin;

class User {
    // 微信用户相关接口
}

use + 别名

use App\Domain\User as DomainUser;
use App\Model\User as ModelUser;

$domain = new DomainUser();
$model = new ModelUser();

// 或使用完整类名
$domain = new \App\Domain\User();

composer.json 配置

{
    "autoload": {
        "psr-4": {
            "App\\": "src/app/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "App\\Test\\": "tests/"
        }
    }
}

全局函数

// src/app/functions.php
namespace App;

function hello() {
    return 'world';
}

function now() {
    return date('Y-m-d H:i:s');
}

// 使用
$result = \App\hello();
$time = \App\now();

单元测试

自动生成测试

php ./bin/phalapi-buildtest ./src/app/Api/User.php App\\Api\\User > ./tests/app/Api/User_Test.php

BUILD-OPERATE-CHECK 模式

class PhpUnderControl_AppApiUser_Test extends \PHPUnit_Framework_TestCase
{
    public function testLogin() {
        // BUILD - 构造
        $url = 's=User.Login';
        $params = array('username' => 'test', 'password' => '123456');

        // OPERATE - 操作
        $rs = \PhalApi\Helper\TestRunner::go($url, $params);

        // CHECK - 检验
        $this->assertNotEmpty($rs);
        $this->assertEquals(200, $rs['ret']);
        $this->assertArrayHasKey('user_id', $rs['data']);
    }

    public function testGetUserInfo() {
        $url = 's=User.GetUserInfo';
        $params = array('id' => 1);

        $rs = \PhalApi\Helper\TestRunner::go($url, $params);

        $this->assertEquals(200, $rs['ret']);
        $this->assertEquals(1, $rs['data']['id']);
    }
}

TestRunner 模拟请求

// 模拟 GET 请求
$rs = \PhalApi\Helper\TestRunner::go('s=User.GetUserInfo&id=1');

// 模拟 POST 请求
$rs = \PhalApi\Helper\TestRunner::go('s=User.Login', array(
    'username' => 'test',
    'password' => '123456',
));

// 带自定义配置
$rs = \PhalApi\Helper\TestRunner::go('s=User.GetUserInfo', array('id' => 1), array(
    'HTTP_X_TOKEN' => 'test_token',
));

常见问题

问题 解决方案
中文返回为空 检查 json_encode 编码,确保数据库 UTF8
跨层调用报错 确认调用关系:Api→Domain→Model
缓存不生效 检查 runtime 目录权限
NotORM 状态问题 每次查询获取新实例 $this->getORM()
全表删除禁止 必须带 WHERE 条件
签名验证失败 确认密钥一致、参数排序规则、编码格式
数据库连接失败 检查 config/dbs.php、MySQL服务、防火墙
参数校验失败 查看 code 错误码、检查参数类型和范围
日志文件过大 FileLogger 自动按天分割,也可手动清理
分表查询不到数据 确认 $id 正确传入 getORM($id)

快速参考表

功能 配置/使用位置 关键类/方法
数据库配置 config/dbs.php NotORMDatabase
缓存配置 config/di.php FileCache/RedisCache/MemcachedCache
日志配置 config/di.php FileLogger
签名配置 config/di.php SimpleMD5Filter
白名单 config/app.php service_whitelist
系统配置 config/sys.php debug/notorm_debug/enable_sql_log
应用配置 config/app.php apiCommonRules
DI服务注册 config/di.php \PhalApi\DI()
接口层 src/app/Api/ extends Api
领域层 src/app/Domain/ 业务逻辑
数据层 src/app/Model/ extends NotORMModel
通用数据 DataApi extends DataApi
参数规则 getRules() 9种类型
在线文档 /docs.php @desc/@return/@exception
单元测试 ./bin/phalapi-buildtest TestRunner::go()
扩展安装 composer.json phalapi/*
环境模式 API_MODE dev/test/prod
加密 PhalApi\Crypt McryptCrypt/RSA
HTTP请求 PhalApi\CUrl get()/post()
Cookie PhalApi\Cookie set()/get()/delete()
工具 PhalApi\Tool getClientIp()/createRandStr()

资源链接

  • 官方文档:http://docs.phalapi.net/#/v2.0/
  • 在线示例:http://demo.phalapi.net/docs.php
  • GitHub:https://github.com/phalapi/phalapi
  • 扩展市场:https://www.phalapi.net/

常见问题

5 问
答案由本站依据条目字段整理
phalapi怎么安装?

在支持 Skills 的客户端里执行:skillhub install user_ef796dd2/phalapi。安装方式为未标注。装完刷新技能列表或重开客户端。

phalapi支持哪些客户端?

资料没有标注宿主客户端,但只要客户端支持 Skills(Claude、Codex、Cursor 等),一般都能加载。

phalapi权限高吗,安全吗?

权限级别为未标注权限。安装前先看它会读取或写入哪些内容。

phalapi收费吗?

本站不代收费用,也没有标注具体价格。是否收费取决于技能本身和所用的模型或客户端,正式使用前按作者说明确认。

phalapi用什么许可证?

许可证标注为 未说明(许可证不明确)。商用或二次分发前请到仓库确认条款原文。

热门专题

按场景挑技能
全部专题 →

技能内容以作者仓库为准;分类、权限级别与许可证状态的中文说明为中文整理,最近核验 未标注。