Skip to content

风音框架 2.0 迁移说明 ​

2.0 是一次不保留 API 兼容层的大版本改版。旧的门面层、全局函数、点分模式号与数字码配置全部移除,改由具名类与具名枚举承担。本文逐项列出旧写法与新写法的对应关系,供接入方按表改造。

一、改动概览 ​

维度1.x2.0
安装方式解压框架包到 extend/fxri/basecomposer require fxri/fxyin
加载方式自带 autoload.php + Loader 注册Composer PSR-4,Fxri\ → src/
入口\fxyin\App::init() 隐式初始化KernelBuilder::make()->build() 显式装配
调用方式\fxapp\Base::config() 等静态门面Kernel 实例 + Fxri\* 纯静态工具类
模式选择点分数字串(1.1.2)与整型 type 参数具名枚举 + 链式方法
响应结构配置驱动的 6 元位置数组Envelope 固定四字段
错误处理fxy_echo 返回数组、throwable() 直接 exit抛异常,由接入层统一映射为信封
PHP 版本7.1 ~ 8.48.2 起

二、安装与装配 ​

bash
composer require fxri/fxyin

最小装配示例:

php
<?php

declare(strict_types=1);

use Fxri\KernelBuilder;
use Fxri\Translation\ArrayTranslator;

$kernel = KernelBuilder::make()
    ->withConfigDir(__DIR__ . '/config')
    ->withTranslator(ArrayTranslator::fromDirectory(__DIR__ . '/language/zh-cn'))
    ->build();

// 取配置
$name = $kernel->config()->get('app.name', '未命名');

// 取翻译
echo $kernel->trans('欢迎');

装配项说明:

方法作用
withConfigDir(string $directory)追加配置目录,后追加者覆盖同名文件
withLogger(LoggerInterface $logger)注入 PSR-3 日志
withTranslator(TranslatorInterface $translator)注入翻译器
withHttpClient(object $client)注入 PSR-18 客户端
withAdapter(object $adapter)注入接入方适配器(如 ThinkPHP 容器适配)

配置文件按「文件名即分组名」加载,config/app.php 返回的数组整体位于 app 键下,用 $kernel->config()->get('app.name') 取值。

三、命名空间与类映射 ​

旧新
\fxyin\AppFxri\KernelBuilder、Fxri\Kernel
\fxyin\ConfigFxri\Config\Config、Fxri\Config\ConfigLoader
\fxyin\EnvFxri\Config\Environment、Fxri\Http\ServerContext
\fxyin\LangFxri\Translation\ArrayTranslator
\fxyin\CookieFxri\Http\Cookie\CookieJar
\fxyin\DirFxri\File\Filesystem、Fxri\File\Path
\fxyin\LoaderComposer PSR-4(不再需要)
\fxyin\Facade移除,改用 Kernel 与纯静态类
\fxapp\BaseFxri\Kernel、Fxri\Http\*、Fxri\Translation\*
\fxapp\ClientFxri\Http\ClientInfo
\fxapp\DataFxri\Data\*、Fxri\Sql\*
\fxapp\FileFxri\File\*、Fxri\Support\Formatter
\fxapp\MathFxri\Support\Random
\fxapp\ParamFxri\Param\*
\fxapp\SafeFxri\Security\*
\fxapp\ServerFxri\Http\Envelope、Responder、ServerContext、RequestContext
\fxapp\ServiceFxri\Http\HttpClient\Client、ClientFactory
\fxapp\TextFxri\Text\*、Fxri\Support\Type
\fxapp\ViewFxri\Http\View、Fxri\Http\Renderer

旧门面 \fxapp\Base ~ \fxapp\View 与 app/controller/facade/ 一并移除,不再提供任何转发入口。

四、数字码全部改为具名枚举 ​

4.1 数字码总览 ​

旧位置旧数字码新写法
Param::define()1.1.1、1.1.2 …Shape 链式组合,见 4.2
Param::url()1.1.1、1.1.3、1.1、1.2、2.1Url::build()、Url::query()、Url::withQuery()
facade.data.where-1 ~ 6WhereBuilder,见 4.4
facade.server.echo.template0 ~ 5Envelope 固定四字段,见 4.5
facade.server.echo.format1 ~ 5Envelope::toArray()
Data::fieldJson()1、2FieldJsonMode::Quoted、FieldJsonMode::Raw
Data::fieldText()1、2、3FieldTextMode::Keep、ReplaceEmpty、CastInt
Data::fieldDate()1、2、3DateGranularity::DateTime、Date、Time
Data::whereMake()1、2WhereBuilder::build()、Sql\Expression
Data::paramEmpty()1、2NullPolicy::Blank、NullPolicy::StrictNull
Client::ip()0、1ClientInfo::ip()、Text\Ip::toLong()
Client::browser()、Client::system()-1、1、2CaseFormat::Original、Lower、Upper
Base::ipv4()、Text::ipv4()encode、decodeText\Ip::toLong()、Text\Ip::fromLong()
Math::rand()0、1RandomCharset::Alnum、RandomCharset::Numeric
Text::uuid()mode 1/2/3;style 1~4UuidMode + UuidStyle
Safe::md5()1、2HashLength::Full32、HashLength::Short16
Base::load()null、'data'无等价实现,项目侧直接 require
Server::format()1、2无等价实现,见 4.5

4.2 Param::define() 模式号 → Shape ​

旧调用形如 \fxapp\Param::define([$input, $defaults], '1.1.2'),其中第一项是待定形数据、第二项是键与默认值。新写法把模式号拆成链式方法:

旧模式号旧语义新写法
1.1.1以输入为基底,键不存在时填默认值Shape::merge()->fillWhenAbsent()
1.1.2以输入为基底,键不存在或为空串时填默认值Shape::merge()->fillWhenBlank()
1.1.3同 1.1.1,且对声明的键做 JSON 解码Shape::merge()->fillWhenAbsent()->json()
1.2.1以输入为基底,键不存在时置 nullShape::merge()->nullWhenAbsent()
1.2.2以输入为基底,键不存在或为空串时置 nullShape::merge()->nullWhenBlank()
1.2.3同 1.2.2,且对声明的键做 JSON 解码Shape::merge()->nullWhenBlank()->json()
1.2.4以输入为基底,键值按逗号拆成数组Shape::merge()->csv()
1.3.1默认值非 null 时优先于输入Shape::merge()->defaultsFirst()
1.3.2同 1.3.1;默认值为 null 时按「不存在或空串」置 nullShape::merge()->defaultsFirst()->nullWhenBlank()
2.1.1只保留声明的键,不存在时填默认值Shape::only()->fillWhenAbsent()
2.1.2只保留声明的键,不存在或为空串时填默认值Shape::only()->fillWhenBlank()
2.2.1只保留声明的键,不存在时置 nullShape::only()->nullWhenAbsent()
2.2.2只保留声明的键,不存在或为空串时置 nullShape::only()->nullWhenBlank()

改造示例:

php
// 1.x
$param = \fxapp\Param::define([$input, ['page' => 1, 'size' => 20]], '2.1.2');

// 2.0
use Fxri\Param\Shape;

$param = Shape::only()->fillWhenBlank()->apply($input, ['page' => 1, 'size' => 20]);

多个定形步骤串联时用 Pipeline:

php
use Fxri\Param\Definition;
use Fxri\Param\Pipeline;
use Fxri\Param\Shape;

$param = Pipeline::make(
    Definition::make(['page' => 1], Shape::only()->fillWhenAbsent()),
    Definition::make(['filters' => []], Shape::merge()->fillWhenAbsent()->json()),
)->resolve($input);

4.3 Param::url() 模式号 → Url ​

旧 Param::url($data) 内部用 3 个点分模式号补默认值,再按 $data['type'] 的 1.1 / 1.2 / 2.1 分发行为:

旧行为新写法
补 type / url / name 默认值Shape::merge()->fillWhenAbsent()
补 param 并 JSON 解码Shape::merge()->fillWhenAbsent()->json()
type = 1.1 由路径与参数拼装地址Url::build($path, $query, $fragment)
type = 1.2 解析当前地址并改写参数Url::withQuery($url, $query)
type = 2.1 从地址中取参数Url::query($url)
php
// 1.x
$url = \fxapp\Param::url(['type' => '1.1', 'url' => '/list', 'param' => ['page' => 2]]);

// 2.0
use Fxri\Param\Url;

$url = Url::build('/list', ['page' => 2]);

4.4 facade.data.where 8 个数字键 → WhereBuilder ​

旧配置以位置数字描述条件元组,改由具名方法与枚举承担:

旧键旧含义新写法
-1原始表达式WhereBuilder::compare() 或 Sql\Expression::make()
0键名作为 column 参数直接传入
1键值作为 value 参数直接传入
2方法(=、in、like 等)eq()、in()、like() 等具名方法
3逻辑(and / or)and()、or()
4分组group(Closure, ?Boolean)
5取反not()
6大小写敏感Collation::CaseSensitive / CaseInsensitive
php
// 1.x
$where = \fxapp\Data::where([
    ['build', 'status', 'enabled', '=', 'and', '1', 0, 1],
    ['build', 'name', '风音', 'like', 'and', '1', 0, 1],
]);

// 2.0
use Fxri\Sql\Boolean;
use Fxri\Sql\Collation;
use Fxri\Sql\WhereBuilder;

$where = WhereBuilder::make()
    ->eq('status', 'enabled')
    ->and()
    ->like('name', '风音')
    ->build();

分组与取反:

php
$where = WhereBuilder::make()
    ->eq('enabled', 1)
    ->and()
    ->group(static function (WhereBuilder $inner): void {
        $inner->eq('type', 'a')->or()->eq('type', 'b');
    }, Boolean::Or)
    ->not()
    ->build();

旧 whereSafe()、whereFilter()、whereBuild()、whereAssemble() 不再保留:WhereBuilder 全部使用绑定参数,字符串白名单过滤已无必要;build() 返回的 Sql 对象同时携带 SQL 片段与绑定值。

4.5 server.echo 两段配置 → Envelope ​

旧响应由 facade.server.echo.template(6 个位置)与 facade.server.echo.format(5 个位置到键名的映射)两段配置驱动:

旧位置旧含义新字段
0逻辑状态Envelope::$ok(ok)
1状态代码Envelope::$code(code)
2提示信息Envelope::$message(message)
3响应数据Envelope::$data(data)
4扩展数据并入 message 或 data,不再单独留位
5请求时间由接入层自行补充,框架不再内置
php
// 1.x
return \fxapp\Base::echo('请求成功', 0, $data);

// 2.0
use Fxri\Http\Envelope;

return Envelope::success($data, '请求成功');

注意两点行为变化:

  • code 由整型改为字符串,成功固定为 Envelope::OK('ok'),构造期不接受空串。
  • 旧 extend 与 time 两个位置不再存在,需要保留时由接入层在 Envelope::toArray() 之外自行追加。

五、全局函数迁移 ​

5.1 11 个 is_* 校验函数 ​

旧函数新写法
is_json($data)Fxri\Support\Type::isJson()
is_blank($data)Fxri\Support\Type::isBlank()
is_time($time, $format)Fxri\Support\Type::isTime()
is_function($data)Fxri\Support\Type::isCallable()
is_mobile($data)Fxri\Support\Type::isMobile()
is_email($data)Fxri\Support\Type::isEmail()
is_zipcode($data)Fxri\Support\Type::isZipcode()
is_ipv4($data)Fxri\Support\Type::isIpv4()
is_ipv6($data)Fxri\Support\Type::isIpv6()
is_url($data)Fxri\Support\Type::isUrl()
is_ip($data)Fxri\Support\Type::isIp()

5.2 7 个 fxy_* 函数 ​

旧函数新写法
fxy_lang($name, $vars, $lang)$kernel->trans($id, $parameters)
fxy_config(...$vars)$kernel->config()->get($name, $default)
fxy_cookie(...$vars)Fxri\Http\Cookie\CookieJar
fxy_env(...$vars)Fxri\Http\ServerContext、Fxri\Config\Environment
fxy_dump(...$vars)Fxri\Support\Dump::write(...)
fxy_json($var, $type, $param)Fxri\Param\Json::encode()、Json::decode()
fxy_echo($message, $code, $data, $extend)Fxri\Http\Envelope + Fxri\Http\Responder

六、响应与异常 ​

旧 Server::format() 按 type 决定输出结构,Base::throwable() 在非调试环境下直接 exit 输出。2.0 改为「业务抛异常、接入层统一映射」:

场景旧写法新写法
校验失败return \fxapp\Base::echo('参数不合法', 0)throw new Fxri\Exception\ValidationException('参数不合法')
数据未变化return \fxapp\Data::updateContrast(...)throw new Fxri\Exception\SameDataException('数据相同')
未知异常\fxapp\Base::throwable('系统异常')交接入层捕获并映射,如 Fxri\Integration\ThinkPHP\ExceptionHandler
输出响应\fxapp\Server::format($echo, 2)Fxri\Http\Responder::format($envelope)

Server::format($data, 2) 的「按 facade.server.echo.format 映射键名」能力没有等价实现,键名已在 Envelope::toArray() 中固定,不再可配置。

七、门面方法逐项对照 ​

7.1 \fxapp\Base ​

旧方法新写法
load($file, $type)无等价实现,项目侧 require / require_once
lang($name, $vars, $lang)$kernel->trans($name, $vars)
langList($name, $vars, $lang)无等价实现,ArrayTranslator::trans() 不做语言相关拼接
langParse($name)无等价实现,同上
config(...$vars)$kernel->config()->get()
cookie(...$vars)CookieJar::get()、CookieJar::set()
env(...$vars)ServerContext::get()、Environment::get()
dump(...$vars)Dump::write(...)
json($data, $type, $param)Json::encode()、Json::decode()
ipv4($data, $type)Ip::toLong()、Ip::fromLong()
crypt($data, $type, $param)Cipher::encrypt()、Cipher::decrypt();旧数据用 LegacyCipher::decrypt()
throwable($message)抛异常,由接入层处理
echo($message, $code, $data, $extend)Envelope::success()、Envelope::failure()

7.2 \fxapp\Client ​

旧方法新写法
ip($type = 0)ClientInfo::ip();需要整型时用 Ip::toLong()
browser($type = -1)ClientInfo::browser(CaseFormat::Original)
system($type = -1)ClientInfo::system(CaseFormat::Original)
param($param, $method)无等价实现,直接读 RequestContext 与 ServerContext

7.3 \fxapp\Data ​

旧方法新写法
where($data, $param)WhereBuilder,见 4.4
whereSafe($value, &$method, $case)无等价实现,绑定参数后不再需要白名单
whereFilter($value, $method, $case)无等价实现,同上
whereBuild($key, $value, $method)WhereBuilder::eq()、in()、like() 等
whereAssemble($data)WhereBuilder::build()
whereMake($data, $type)WhereBuilder::build();需要前缀时用 Expression 拼接
insert($table, $data)StatementBuilder::insert()
update($table, $data, $param)StatementBuilder::update()
updateContrast($data_new, $data_old)Diff::make(),未变化时抛 SameDataException
storeUpperLevel(...)无等价实现,项目侧递归查询
storeLowerLevel(...)无等价实现,同上
fieldDistance(...)无等价实现,用 Sql\Expression 书写
fieldInitial($field)无等价实现,用 Sql\Expression 书写
fieldDivision(...)无等价实现,用 Sql\Expression 书写
fieldJson($field, $replace, $param)Field::json($column, $path, FieldJsonMode::Quoted)
fieldText($field, $replace, $param)Field::text($column, $replace, FieldTextMode::Keep)
fieldDate($field, $replace, $param)Field::date($column, DateGranularity::DateTime, $replace)
fieldAlias($data, $alias, $delimiter)无等价实现,项目侧拼接
fieldEscape($data, $delimiter)无等价实现,Expression 内自行反引号
htmlFilter($data, $flags)Html::escape($data)
htmlRemove($data, $flags)Html::strip($data, $allowed)
listToTree($list, ...)Tree::fromList($list, $rootId, $idKey, $parentKey, $childKey)
paramRepair($param)无等价实现,项目侧按需补键
paramFilter($param)Data\Param::filter($param)
paramEmpty($param, $type)Data\Param::missing($param, NullPolicy::Blank)
paramExist($param)[] === Data\Param::missing($param, NullPolicy::StrictNull)

7.4 \fxapp\File ​

旧方法新写法
formatSize($size)Formatter::size($bytes)
getList($path, $ext, $limit)Filesystem::listFiles($directory),扩展名过滤由调用方处理
moveDirectory($oldpath, $newpath)Filesystem::moveDirectory()
deleteDirectory($path)Filesystem::deleteDirectory()
getMediaInfo($var, $type)MediaInfo::mime()、MediaInfo::extension()

7.5 \fxapp\Math ​

旧方法新写法
rand($length, $type)Random::string($length, RandomCharset::Alnum)

7.6 \fxapp\Param ​

旧方法新写法
init()移除,参数由调用方直接传入
define($param, $mode)Shape 链式组合,见 4.2
array($param, $limit, $filter)无等价实现,直接数组操作
object($param, $limit, $filter)无等价实现,(object) 强转或自建
pick($base, $data)Picker::only()
append(...$args)Pipeline
merge($limit, $cover, $type, ...$args)Merger::merge()、Merger::mergeKeepBlank()
cover($args, $limit, $cover, $type)Merger::merge()
url($data)Url::build()、Url::query()、Url::withQuery()
json($var, $type, $param)Json::encode()、Json::decode()

7.7 \fxapp\Safe ​

旧方法新写法
crypt($data, $type, $param)Cipher::encrypt()、Cipher::decrypt();旧数据用 LegacyCipher::decrypt()
md5($data, $type)Hash::md5($data, HashLength::Full32)
token($data, $type)Token::make() 签发、Token::verify() 校验
rsapri($data, $type, $param)Rsa::sign()、Rsa::decrypt()
rsapub($data, $type, $param)Rsa::verify()、Rsa::encrypt()
rsapem($data)无等价实现,Rsa::generate() 直接产出密钥

7.8 \fxapp\Server ​

旧方法新写法
echo()Envelope::success() 的模板等价物
ip()ClientInfo::ip()
system($type)ClientInfo::system(CaseFormat::Original)
format($data, $type)Envelope::toArray()、JsonFormatter::format()
env()ServerContext::fromGlobals()、Environment::fromFile()
branch()无等价实现,项目侧读取自身配置

7.9 \fxapp\Service ​

旧方法新写法
http($url, $data, $header, $method, $option)HttpClient\Client::send()
httpDown($url, $file)无等价实现,项目侧用 HttpClient\Client 自行落盘

7.10 \fxapp\Text ​

旧方法新写法
uuid($mode, $param)Uuid::make(UuidMode, $seed, UuidStyle)
implode($delimiter, $data, $explode, $unique)Str::implode($glue, $values, $unique)
explode($delimiter, $data, $unique, $limit)Str::explode($separator, $value, $unique)
splice($string, $value, $delimiter)Str::splice($value, $append, $glue)
strlen($string, $start, $end)Str::length()、Str::isLength()
letters($var, $in_charset, $out_charset)无等价实现,mb_convert_encoding()
letter($var, $in_charset, $out_charset)无等价实现,同上
timeRange($time, $start, $end)无等价实现,项目侧比较
timeChange($time, $type, $format)Time::parse()、Time::format()
timeMilli($mtime)Time::milli()
timeFormat($time, $param)无等价实现,按 DateGranularity 组合
strEncode($data)Encode::base64Encode()
strEncodeMerge($data)无等价实现,项目侧循环
strDecode($data)Encode::base64Decode()
strDecodeMerge($data)无等价实现,项目侧循环
ipv4($data, $type)Ip::toLong()、Ip::fromLong()
convert($data, $type)无等价实现,按需用 mb_convert_encoding()
throwable($th, $type, $param)无等价实现,接入层自行渲染

7.11 \fxapp\View ​

旧方法新写法
echo($data, $type)View::render()、Renderer::render()

八、接入方 extend/fxri/data 处置 ​

旧分发方式下,接入方在本项目之外维护 extend/fxri/data 目录(框架包放在 extend/fxri/base)。该目录没有框架源码,全部是个性化数据与环境差异,按以下四类处置:

类别典型内容处置
上收到框架语言词条、请求环境(方案、主机、路径、方法、来源参数)、响应信封结构框架已内置等价实现:语言词条用 Translation\PhpFileLoader::loadDirectory() 读入 ArrayTranslator;请求环境用 ServerContext / RequestContext;响应结构用 Envelope
保留差异迁入项目配置项目私有配置项、应用名称与目录、Cookie 与 Session 参数、媒体工具路径迁入项目自己的配置目录,由 KernelBuilder::withConfigDir() 加载
项目侧改写机制依赖 facade.data.where 数字位置拼条件的代码、继承旧门面的自定义类、依赖 server.echo.format 改键名的序列化改用 WhereBuilder、Envelope,或改为组合调用 Fxri\*;不再支持继承门面
直接删除extend/fxri/base(框架本体)、旧引导文件 autoload.php / config.php、app/store/common.php 式启动脚本、三段数字键配置删除,改由 Composer 安装与 KernelBuilder 装配

app/language/{zh-cn,en-us} 下的词条文件属于纯数据,可作为 PhpFileLoader::loadDirectory() 的输入直接复用。

九、迁移检查清单 ​

  • 全仓检索 \fxapp\、\fxyin\、fxy_echo、fxy_config、fxy_lang、fxy_env、fxy_cookie、fxy_dump、fxy_json,除本文档外应归零。
  • 全仓检索点分模式号(形如 '1.1.2')与 facade.data.where、facade.server.echo,应归零。
  • 旧响应数组的下标访问($echo[0] ~ $echo[5])改为 Envelope::isOk()、code()、message()、data()。
  • 旧 \fxapp\Data::field*() 生成的字符串 SQL 改为 Data\Sql 对象,绑定值随对象传递。
  • 加密:旧 Safe::crypt() 产出的密文只能用 Security\LegacyCipher::decrypt() 读取,新数据统一用 Cipher。
  • 依赖注入:把 LoggerInterface、TranslatorInterface、HTTP 客户端从门面静态调用改为 KernelBuilder 注入。
  • 入口:删除 \fxyin\App::init() 与 autoload.php 引导,改为 Composer 自动加载 + KernelBuilder。

十、不再提供的能力 ​

以下能力在 2.0 中没有等价实现,需要接入方按业务自行实现,避免误以为只是改了名字:

  • 门面静态转发(Facade::__callStatic)与 \fxapp\* 全部类名。
  • 全局函数与函数文件自动加载(app/function/ 目录约定)。
  • 配置驱动的响应结构(server.echo.template / server.echo.format)与 extend、time 两个响应位。
  • 条件拼接的字符串白名单过滤(whereSafe / whereFilter)。
  • 递归上级 / 下级存储查询(storeUpperLevel / storeLowerLevel)。
  • 字段级别的距离、首字母、除法表达式(fieldDistance / fieldInitial / fieldDivision)。
  • 字段别名与字段转义(fieldAlias / fieldEscape)。
  • 语言列表拼接与按语言切换连接符(langList / langParse)。
  • 编码转换助手(letters / letter / convert / strEncodeMerge / strDecodeMerge)。
  • 应用目录约定式启动(\fxyin\App::init() 扫描 function/、config/、language/、store/)。
  • 内置路由分发(\fxyin\App::run())。

十一、相关文档 ​

  • 快速开始:从零安装、装配与最小可运行示例。
  • 更新日志:各版本完整变更条目,含 2.0 的分组说明。

Apache License 2.0