Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
206 lines (159 sloc) 5.06 KB

参数绑定

实现接口时,通常需要从 http 请求中提取数据,作为方法的输入参数,并将方法的返回值转换成 http 的输出。参数绑定功能即可以帮你完成上述工作。

1. 输入绑定

1.1. 根据方法定义绑定

默认情况下,框架会从http请求中提取和方法的参数名同名的变量,作为函数的参数。比如:

/**
 * @route GET /books/
 */
public function getBooks($offsit, $limit)

上述代码,对应的 http 请求形式为 GET /books/?offsit=0&limit=10。在此默认请求下:

  • 如果路由 uri 中定义了变量,参数将优先选取 uri 变量。如:
/**
 * @route GET /books/{id}
 */
public function getBook($id)

其中 $id 取自 uri。

  • 对于没有 BODY 的 http 请求(GET、HEAD、OPTION、DELETE),参数来自 querystring 。

  • 其他请求(POST、PUT、OPTION),参数先取 querystring,如果没有,再取 BODY。

1.2. @param

如果在方法的注释中,标注了 @param,就会有用 @param 的绑定信息覆盖默认来自函数定义的绑定信息。@param 可以指定变量的类型,而原函数定义中只能在参数是数组或者对象时才能指定类型。@param 的语法为标准 PHP Document 的语法。

/**
 * @route GET /books/
 * @param int $offsit
 * @param int $limit
 */
public function getBooks($offsit, $limit)

以上代码,除了绑定变量外,还指定了变量类型,即如果输入值无法转换成 int,将返回 400 BadRequest 错误。未指定@param 时,参数的类型默认为 mixed。

1.3. 输入对象参数

输入参数除了是原生类型外,还可以是对象(这里我们把只有属性和 get、set 方法的对象,称为实体(Entity))。如:

/**
 * @route POST /books/
 * @param Book $book {@bind request.request} 将$_POST 内容转换成Book实例
 */
public function createBook(Book $bok)

其中 Book 的的定义:

/**
 * 图书信息
 */
class Book
{
    /**
     * @var int
     * @v optional
     */
    public $id;
    /**
     * 书名
     * @var string
     */
    public $name='';

    /**
     * 简介
     * @var string
     * @v lengthMax:200
     */
    public $brief='';

    /**
     * 图片url
     * @var string[]
     */
    public $pictures=[];
}

框架对 http 请求到实体的转换,有一套自己的逻辑:

  • @var 指定属性的类型,如果类型不匹配,实例化将抛出 InvalidArgumentException 异常
  • 如果不标注 @var,则默认类型为mixed
  • 如果属性有默认值,表示此属性可选,否则认为此属性必选
  • 支持 @v 定义校验规则
  • 实体可以嵌套

1.4. 参数默认值

如果想指定某个输入参数可选,只需给方法参数设置一个默认值。比如:

/**
 * @route GET /books/
 * @param int $offsit
 * @param int $limit
 */
public function getBooks($offsit=0, $limit=10)

注意:php 方法的默认参数, 必须放在方法的最后

2. 输出绑定

2.1. 绑定return

默认情况下,函数的返回值将 jsonencode 后,作为 body 输出。如

/**
 * @route GET /books/{id}
 */
public function getBook($id)
{
    return ['name'=>'PhpBook', 'desc'=>'PhpBook Document'];
}

curl 请求将得到以下结果

$ curl "http://localhost/books/1"
{
    "name": "PhpBook",
    "desc": "PhpBook Document"
}

注意,这里为便于演示,直接在方法中返回了数组(其实这在其他语言里算对象),但你应该为这种返回定义一个类,首先,有很多改善代码质量的理由鼓励使用对象替代这类数组,其次在自动生成文档时,这类数组无发被结构化描述。

2.2. 绑定引用参数

如果方法的参数是引用类型,则这个参数将不会从请求中获取,而是作为输出。比如:

/**
 * @route GET /books/
 * @param int $offsit
 * @param int $limit
 * @return Books[]
 */
public function getBooks($offsit=0, $limit=10, &$total)
{
    $total = 1;
    return [new Books()];
}

curl 请求将得到以下结果

$ curl "http://localhost/books"
{
    "total": 1,
    "data": [
        {
            "name":null, 
            "desc":null
        }
    ]
}

可以看到,$total 输出到了 http body 中。 注意:当接口存在引用参数时,接口的返回值将会被默认绑定到response.content.data,效果和声明{@bind response.content.data}一致。

3. @bind

通过@bind,可以改变默认的绑定关系,将参数与其他输入项绑定,如:

/**
 * @route GET /books/
 * @return Books[] {@bind response.content.books}
 */
public function getBooks($offsit=0, $limit=10, &$total)

表示将返回绑定到响应 body 的 books 变量(响应默认是 json)。

3.1. 绑定输入

  • 请求Body: request.request
  • Query String: request.query
  • Cookie: request.cookies
  • **请求Header:**request.headers
  • **文件:**request.files

3.2. 绑定输出

  • 响应Body: response.content
  • Cookie: response.cookies
  • **请求Header:**response.headers
You can’t perform that action at this time.