×
PhalApi 2.x 前言

PhalApi 2.x 快速开发

1.1 下载与安装1.2 运行Hello World1.3 如何请求接口服务1.4 接口响应与在线调试1.5 Api接口层1.6 Domain领域层和ADM模式1.7 Model数据层与数据库操作1.8 单元测试1.9 自动加载和PSR-41.10 接口文档

PhalApi 2.x 数据库

2.1 数据库链接2.2 数据库与NotORM2.3 数据库使用和查询2.4 数据库分库分表策略2.5 连接多个数据库2.6 打印和保存SQL语句2.7 定制你的Model基类

PhalApi 2.x 高级专题

3.1 PhalApi 2.x 接口参数3.2 PhalApi 2.x 配置3.3 PhalApi 2.x 日志3.4 PhalApi 2.x 缓存3.5 PhalApi 2.x 过滤器3.6 PhalApi 2.x COOKIE3.7 PhalApi 2.x 加密3.8 PhalApi 2.x 国际化3.9 PhalApi 2.x CURL请求3.10 PhalApi 2.x 工具和杂项3.11 PhalApi 2.x DI服务汇总

PhalApi 2.x 发现更多

4.1 PhalApi 2.x 扩展类库4.2 PhalApi 2.x SDK包的使用4.3 PhalApi 2.x 脚本命令

关于PhalApi 2.x

5.1 PhalApi 2.x 版本完美诠释5.2 PhalApi 2.x 升级指南5.3 PhalApi 2.x VS PhalApi 1.x

1.5 PhalApi 2.x Api接口层


Api接口层称为接口服务层,负责对客户端的请求进行响应,处理接收客户端传递的参数,进行高层决策并对领域业务层进行调度,最后将处理结果返回给客户端。

接口参数规则配置

接口参数,对于接口服务本身来说,是非常重要的。对于外部调用的客户端来说,同等重要。对于接口参数,我们希望能够既减轻后台开发对接口参数获取、判断、验证、文档编写的痛苦;又能方便客户端快速调用,明确参数的意义。由此,我们引入了参数规则这一概念,即:通过配置参数的规则,自动实现对参数的获取和验证,同时自动生成在线接口文档。

一个简单的示例

假设我们现在需要提供一个用户登录的接口,接口参数有用户名和密码,那么新增的接口类和规则如下:

// 文件 ./src/app/Api/User.php
<?php
namespace AppApi;

use PhalApiApi;

class User extends Api {

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

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

当请求此接口服务,并类似这样带上username和password参数时:

/?s=User.Login&username=dogstar&password=123456

就可以得到这样的返回结果。

{"ret":0,"data":{"username":"dogstar","password":"123456"},"msg":""}

参数规则格式

参数规则是针对各个接口服务而配置的多维规则数组,由接口类的getRules()方法返回。其中,

  • 一维下标是接口类的方法名,对应接口服务的Action;
  • 二维下标是类属性名称,对应在服务端获取通过验证和转换化的最终客户端参数;
  • 三维下标name是接口参数名称,对应外部客户端请求时需要提供的参数名称。

小结如下:

    public function getRules() {
        return array(
            '接口类方法名' => array(
                '接口类属性' => array('name' => '接口参数名称', ... ... ),
            ),
        );
    }

在接口实现类里面getRules()成员方法配置参数规则后,便可以通过类属性的方式,根据配置指定的名称获取对应的接口参数,如上面的:$this->username$this->password

三级参数规则配置

参数规则主要有三种,分别是:系统参数规则、应用参数规则、接口参数规则。

系统参数

系统参数是指被框架保留使用的参数。目前已被PhalApi占用的系统参数只有一个,即:service参数(缩写为s参数),前面已有介绍。

应用参数

应用参数是指在一个接口系统中,全部项目的全部接口都需要的参数,或者通用的参数。假如我们的商城接口系统中全部的接口服务都需要必须的签名sign参数,以及非必须的版本号,则可以在./config/app.php中的apiCommonRules进行应用参数规则的配置:

<?php
return array(
    /**
     * 应用接口层的统一参数
     */
    'apiCommonRules' => array(
        //签名
        'sign' => array(
            'name' => 'sign', 'require' => true,
        ),
        //客户端App版本号,默认为:1.4.0
        'version' => array(
            'name' => 'version', 'default' => '1.4.0', 
        ),
    ),
)

接口参数

接口参数是指各个具体的接口服务所需要的参数,为特定的接口服务所持有,独立配置。并且进一步在内部又细分为两种:

  • 通用接口参数规则:使用*作为下标,对当前接口类全部的方法有效。
  • 指定接口参数规则:使用方法名作为下标,只对接口类的特定某个方法有效。

例如为了加强安全性,需要为全部的用户接口服务都加上长度为4位的验证码参数:

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

现在,当再次请求用户登录接口,除了要提供用户名和密码外,我们还要提供验证码code参数。并且,对于ApiUser类的其他方法也一样。

多个参数规则时的优先级

当同一个参数规则分别在应用参数、通用接口参数及指定接口参数出现时,后面的规则会覆盖前面的,即具体化的规则会替换通用的规则,以保证接口参数满足特定场合的定制要求。

简而言之,多个参数规则的优先级从高到下,分别是(正如你想到的那样):

  • 1、指定接口参数规则
  • 2、通用接口参数规则
  • 3、应用参数规则
  • 4、系统参数规则

参数规则配置详细说明

具体的参数规则,根据不同的类型有不同的配置选项,以及一些公共的配置选项。目前,主要的类型有:字符串、整数、浮点数、布尔值、时间戳/日期、数组、枚举类型、文件上传和回调函数。

类型 type 参数名称 name 是否必须 require 默认值 default 最小值 min,最大值 max 更多配置选项(无特殊说明,均为可选)
字符串 string TRUE/FALSE,默认FALSE 应为字符串 可选 regex选项用于配置正则匹配的规则;format选项用于定义字符编码的类型,如utf8、gbk、gb2312等
整数 int TRUE/FALSE,默认FALSE 应为整数 可选 ---
浮点数 float TRUE/FALSE,默认FALSE 应为浮点数 可选 ---
布尔值 boolean TRUE/FALSE,默认FALSE true/false --- 以下值会转换为TRUE:ok,true,success,on,yes,1,以及其他PHP作为TRUE的值
时间戳/日期 date TRUE/FALSE,默认FALSE 日期字符串 可选,仅当为format配置为timestamp时才判断,且最值应为时间戳 format选项用于配置格式,为timestamp时会将字符串的日期转换为时间戳
数组 array TRUE/FALSE,默认FALSE 字符串或者数组,为非数组会自动转换/解析成数组 可选,判断数组元素个数 format选项用于配置数组和格式,为explode时根据separator选项将字符串分割成数组, 为json时进行JSON解析
枚举 enum TRUE/FALSE,默认FALSE 应为range选项中的某个元素 --- 必须的range选项,为一数组,用于指定枚举的集合
文件 file TRUE/FALSE,默认FALSE 数组类型 可选,用于表示文件大小范围,单位为B range选项用于指定可允许上传的文件类型;ext选项用于表示需要过滤的文件扩展名
回调 callable/callback TRUE/FALSE,默认FALSE --- --- callable/callback选项用于设置回调函数,params选项为回调函数的第三个参数(另外第一个为参数值,第二个为所配置的规则)

公共配置选项

公共的配置选项,除了上面的类型、参数名称、是否必须、默认值,还有说明描述、数据来源。下面分别简单说明。

  • 类型 type
    用于指定参数的类型,可以是string、int、float、boolean、date、array、enum、file、callable,或者自定义的类型。未指定时,默认为字符串。

  • 参数名称 name
    接口参数名称,即客户端需要传递的参数名称。与PHP变量规则一样,以下划线或字母开头。此选项必须提供,否则会提示错误。

  • 是否必须require
    为TRUE时,表示此参数为必须值;为FALSE时,表示此参数为可选。未指定时,默认为FALSE。

  • 默认值 default
    未提供接口参数时的默认值。未指定时,默认为NULL。

  • 最小值 min,最大值 max
    部分类型适用。用于指定接口参数的范围,比较时采用的是闭区间,即范围应该为:[min, max]。也可以只使用min或max,若只配置了min,则表示:[min, +∞);若只配置了maz,则表示:(-∞, max]。

  • 说明描述 desc
    用于自动生成在线接口详情文档,对参数的含义和要求进行扼要说明。未指定时,默认为空字符串。

  • 数据来源 source
    指定当前单个参数的数据来源,可以是post、get、cookie、server、request、header、或其他自定义来源。未指定时,默认为统一数据源。目前支持的source与对应的数据源映射关系如下:
source 对应的数据源
post $_POST
get $_GET
cookie $_COOKIE
server $_SERVER
request $_REQUEST
header $_SERVER['HTTP_X']

通过source参数可以轻松、更自由获取不同来源的参数。以下是一些常用的配置示例。

// 获取HTTP请求方法,判断是POST还是GET
'method' => array('name' => 'REQUEST_METHOD', 'source' => 'server'),

// 获取COOKIE中的标识
'is_new_user' => array('name' => 'is_new_user', 'source' => 'cookie'),

// 获取HTTP头部中的编码,判断是否为utf-8
'charset' => array('name' => 'Accept-Charset', 'source' => 'header'),

若配置的source为无效或非法时,则会抛出异常。如配置了'source' => 'NOT_FOUND',会得到:

"msg": "服务器运行错误: 参数规则中未知的数据源:NOT_FOUND"

9种参数类型

对于各种参数类型,结合示例说明如下。

  • 字符串 string

当一个参数规则未指定类型时,默认为string。如最简单的:

array('name' => 'username')

温馨提示:这一小节的参数规则配置示例,都省略了类属性,以关注配置本身的内容。

这样就配置了一个参数规则,接口参数名字叫username,类型为字符串。

一个完整的写法可以为:

array('name' => 'username', 'type' => 'string', 'require' => true, 'default' => 'nobody', 'min' => 1, 'max' => 10)

这里指定了为必选参数,默认值为nobody,且最小长度为1个字符,最大长度为10个字符,若传递的参数长度过长,如&username=alonglonglonglongname,则会异常失败返回:

"msg": "非法请求:username.len应该小于等于10, 但现在username.len = 21"

当需要验证的是中文的话,由于一个中文字符会占用3个字节。所以在min和max验证的时候会出现一些问题。为此,PhalApi提供了format配置选项,用于指定字符集。如:

array('name' => 'username', 'type' => 'string', 'format' => 'utf8', 'min' => 1, 'max' => 10)

我们还可以使用regex下标来进行正则表达式的验证,一个邮箱的例子是:

array('name' => 'email', 'regex' => "/^([0-9A-Za-z\-_\.]+)@([0-9a-z]+\.[a-z]{2,3}(\.[a-z]{2})?)$/i")
  • 整型 int

整型即自然数,包括正数、0和负数。如通常数据库中的id,即可配置成:

array('name' => 'id', 'type' => 'int', 'require' => true, 'min' => 1)

当传递的参数,不在其配置的范围内时,如&id=0,则会异常失败返回:

"msg": "非法请求:id应该大于或等于1, 但现在id = 0"

另外,对于常见的分页参数,可以这样配置:

array('name' => 'page_num', 'type' => 'int', 'min' => 1, 'max' => 20, 'default' => 20)

即每页数量最小1个,最大20个,默认20个。

  • 浮点 float

浮点型,类似整型的配置,此处略。

  • 布尔值 boolean

布尔值,主要是可以对一些字符串转换成布尔值,如ok,true,success,on,yes,以及会被PHP解析成true的字符串,都会转换成TRUE。如通常的“是否记住我”参数,可配置成:

array('name' => 'is_remember_me', 'type' => 'boolean', 'default' => TRUE)

则以下参数,最终服务端会作为TRUE接收。

?is_remember_me=ok
?is_remember_me=true
?is_remember_me=success
?is_remember_me=on
?is_remember_me=yes
?is_remember_me=1
  • 日期 date

日期可以按自己约定的格式传递,默认是作为字符串,此时不支持范围检测。例如配置注册时间:

array('name' => 'register_date', 'type' => 'date')

对应地,register_date=2015-01-31 10:00:00则会被获取到为:"2015-01-31 10:00:00"。

当需要将字符串的日期转换成时间戳时,可追加配置选项'format' => 'timestamp',则配置成:

array('name' => 'register_date', 'type' => 'date', 'format' => 'timestamp')

则上面的参数再请求时,则会被转换成:1422669600。

此时作为时间戳,还可以添加范围检测,如限制时间范围在31号当天:

array('name' => 'register_date', 'type' => 'date', 'format' => 'timestamp', 'min' =>  1422633600, 'max' => 1422719999)

当配置的最小值或最大值为字符串的日期时,会自动先转换成时间戳再进行检测比较。如可以配置成:

array('name' => 'register_date', ... ... 'min' => '2015-01-31 00:00:00', 'max' => '2015-01-31 23:59:59')
  • 数组 array

很多时候在接口进行批量获取时,都需要提供一组参数,如多个ID,多个选项。这时可以使用数组来进行配置。如:

array('name' => 'uids', 'type' => 'array', 'format' => 'explode', 'separator' => ',')

这时接口参数&uids=1,2,3则会被转换成:

array ( 0 => '1', 1 => '2', 2 => '3', )

如果设置了默认值,那么默认值会从字符串,根据相应的format格式进行自动转换。如:

array( ... ... 'default' => '4,5,6')

那么在未传参数的情况下,自动会得到:

array ( 0 => '4', 1 => '5', 2 => '6', )

又如接口需要使用JSON来传递整块参数时,可以这样配置:

array('name' => 'params', 'type' => 'array', 'format' => 'json')

对应地,接口参数&params={"username":"test","password":"123456"}则会被转换成:

array ( 'username' => 'test', 'password' => '123456', )

温馨提示:使用JSON传递参数时,建议使用POST方式传递。若使用GET方式,须注意参数长度不应超过浏览器最大限制长度,以及URL编码问。

若使用JSON格式时,设置了默认值为:

array( ... ... 'default' => '{"username":"dogstar","password":"xxxxxx"}')

那么在未传参数的情况下,会得到转换后的:

array ( 'username' => 'dogstar', 'password' => 'xxxxxx', )

特别地,当配置成了数组却未指定格式format时,接口参数会转换成只有一个元素的数组,如接口参数:&name=test,会转换成:

array ( 0 => 'test' )
  • 枚举 enum

在需要对接口参数进行范围限制时,可以使用此枚举型。如对于性别的参数,可以这样配置:

array('name' => 'sex', 'type' => 'enum', 'range' => array('female', 'male'))

当传递的参数不合法时,如&sex=unknow,则会被拦截,返回失败:

"msg": "非法请求:参数sex应该为:female/male,但现在sex = unknow"

关于枚举类型的配置,这里需要特别注意配置时,应尽量使用字符串的值。 因为通常而言,接口通过GET/POST方式获取到的参数都是字符串的,而如果配置规则时指定范围用了整型,会导致底层规则验证时误判。例如接口参数为&type=N,而接口参数规则为:

array('name' => 'type', 'type' => 'enum', 'range' => array(0, 1, 2))

则会出现以下这样的误判:

var_dump(in_array('N', array(0, 1, 2))); // 结果为true,因为 'N' == 0

为了避免这类情况发生,应该使用使用字符串配置范围值,即可这样配置:

array('name' => 'type', 'type' => 'enum', 'range' => array(`0`, `1`, `2`))
  • 文件 file

在需要对上传的文件进行过滤、接收和处理时,可以使用文件类型,如:

array(
    'name' => 'upfile', 
    'type' => 'file', 
    'min' => 0, 
    'max' => 1024 * 1024, 
    'range' => array('image/jpeg', 'image/png') , 
    'ext' => array('jpeg', 'png')
)

其中,min和max分别对应文件大小的范围,单位为字节;range为允许的文件类型,使用数组配置,且不区分大小写。

如果成功,返回的值对应的是$_FILES["upfile"],即会返回:

array(
     'name' => ..., // 被上传文件的名称
     'type' => ..., // 被上传文件的类型
     'size' => ..., // 被上传文件的大小,以字节计
     'tmp_name' => ..., // 存储在服务器的文件的临时副本的名称
)

对应的是:

  • $_FILES["upfile"]["name"] - 被上传文件的名称
  • $_FILES["upfile"]["type"] - 被上传文件的类型
  • $_FILES["upfile"]["size"] - 被上传文件的大小,以字节计
  • $_FILES["upfile"]["tmp_name"] - 存储在服务器的文件的临时副本的名称
  • $_FILES["upfile"]["error"] - 由文件上传导致的错误代码

参考:以上内容来自W3School,文件上传时请使用表单上传,并enctype 属性使用"multipart/form-data"。更多请参考PHP 文件上传

若需要配置默认值default选项,则也应为一数组,且其格式应类似如上。

其中,ext是对文件后缀名进行验证,当如果上传文件后缀名不匹配时将抛出异常。文件扩展名的过滤可以类似这样进行配置:

  • 单个后缀名 - 数组形式

    'ext' => array('jpg')
  • 单个后缀名 - 字符串形式

    'ext' => 'jpg'
  • 多个后缀名 - 数组形式

    'ext' => array('jpg', 'jpeg', 'png', 'bmp')
  • 多个后缀名 - 字符串形式(以英文逗号分割)

    'ext' => 'jpg,jpeg,png,bmp' 
  • 回调 callable/callback

当需要利用已有函数进行自定义验证时,可采用回调参数规则,如配置规则:

array('name' => 'version', 'type' => 'callable', 'callback' => 'App\Common\Request\Version::formatVersion')

然后,回调时将调用下面这个新增的类函数:

<?php
namespace AppCommonRequest;

use PhalApiExceptionBadRequestException;

class Version {

    public static function formatVersion($value, $rule) {
        if (count(explode('.', $value)) < 3) {
            throw new BadRequestException('版本号格式错误');
        }
        return $value;
    }
}

回调函数的签名为:function format($value, $rule, $params),第一个为参数原始值,第二个为所配置的规则,第三个可选参数为配置规则中的params选项。最后应返回转换后的参数值。

接口返回

回顾一下,在PhalApi中,掊口返回的结果的结构为:

{
    "ret": 200, // 状态码
    "data": {
        // 业务数据
    },
    "msg": "" // 错误提示信息
}

正常情况下的返回

正常情况下,在Api层返回的数据结果,会在返回结果的data字段中体现。例如:

class Hello extends Api {

    public function world() {
        return array('title' => 'Hello World!');
    }
}

对应:

{
    "ret": 200,
    "data": {
        "title": "Hello World!"
    },
    "msg": ""
}

成功返回时,状态码ret为200,并且错误信息msg为空。

失败情况下的返回

对于异常情况,包括系统错误或者应用层的错误,可以通过抛出PhalApiException系列的异常,中断请求并返回相关的错误信息。例如:

class Hello extends Api {

    public function fail() {
        throw new BadRequestException('签名失败', 1);
    }
}

会得到以下结果输出:

{
    "ret": 401,
    "data": [],
    "msg": "Bad Request: 签名失败"
}

注释与在线文档

PhalApi提供了自动生成的在线接口文档,对于每一个接口服务,都有对应的在线接口详情文档。如默认接口服务Site.Index的在线接口详情文档为:

此在线接口详情文档,从上到下,依次说明如下。

接口服务名称

接口服务名称是指用于请求时的名称,对应s参数(或service参数)。接口服务的中文名称,为不带任何注解的注释,通常为接口类成员函数的第一行注释。

class Site extends Api {

    /**
     * 默认接口服务
     */
    public function index() {
    }
}

接口说明

接口说明对应接口类成员函数的@desc注释。

class Site extends Api {

    /**
     * 默认接口服务
     * @desc 默认接口服务,当未指定接口服务时执行此接口服务
     */
    public function index() {
    }
}

接口参数

接口参数是根据接口类配置的参数规则自动生成,即对应当前接口类getRules()方法中的返回。其中最后的“说明” 字段对应参数规则中的desc选项。可以配置多个参数规则。此外,配置文件./config/app.php中的公共参数规则也会显示在此接口参数里。

class Site extends Api {

    public function getRules() {
        return array(
            'index' => array(
                'username'  => array('name' => 'username', 'default' => 'PHPer', ),
            ),
        );
    }
}

返回结果

返回结果对应接口类成员函数的@return注释,可以有多组,格式为:@return 返回类型 返回字段 说明

class Site extends Api {

    /**
     * 默认接口服务
     * @desc 默认接口服务,当未指定接口服务时执行此接口服务
     * @return string title 标题
     * @return string content 内容
     * @return string version 版本,格式:X.X.X
     * @return int time 当前时间戳
     */
    public function index() {
    }
}

异常情况

异常情况对应@exception注释,可以有多组,格式为:@exception 错误码 错误描述信息。例如:

    /**
     * @exception 406 签名失败
     */
    public function index() {

刷新后,可以看到新增的异常情况说明。

公共注释

对于当前类的全部函数成员的公共@exception异常情况注释和@return返回结果注释,可在类注释中统一放置。而对于多个类公共的@exception@return```注释,则可以在父类的类注释中统一放置。

也就是说,通过把@exception注解和@return注解移到类注释,可以添加全部函数成员都适用的注解。例如,ApiUser类的全部接口都返回code字段,且都返回400和500异常,则可以:

<?php
namespace AppApi;

use PhalApiApi;

/**
 * @return int code 操作码,0表示成功
 * @exception 400 参数传递错误
 * @exception 500 服务器内部错误
 */

class User extends Api {

这样就不需要在每个函数成员的注释中重复添加注解。此外,也可以在父类的注释中进行添加。对于相同异常码的@exception注解,子类的注释会覆盖父类的注释,方法的注释会覆盖类的注释;而对于相同的返回结果@return注释,也一样。

需要注意的是,注释必须是紧挨在类的前面,而不能是在namespace前面,否则会导致注释解析失败。


分类导航

关注微信下载离线手册

bootwiki移动版 bootwiki
(群号:472910771)