PHP DIY系列–一起手写一个api框架


我们在library\Https目录下新建Request、Response,开始编写请求和输出的代码。

Request

我们实现几个常用的方法,get、post、method等,这里主要用$_SERVER实现,为了复用我们定义了三个私有属性存储get参数、post参数和method。

<?php
/**
* 处理请求
*/

namespace Library\Https;

use Library\Components\Base;

class Request extends Base
{
/**
* 获取请求方法
* @return string
*/
public function getMethod()
{
if (isset($_SERVER['REQUEST_METHOD'])) {
return strtoupper($_SERVER['REQUEST_METHOD']);
}
return 'GET';
}

/**
* 请求头
* @param $name
* @param null $defaultValue
* @return mixed|null
*/
public function getHeader($name, $defaultValue = null)
{
$name = ucfirst($name);
if (function_exists('apache_request_headers')) {
$headers = apache_request_headers();
return $headers[$name]?? $defaultValue;
}
$name = strtoupper($name);
return $_SERVER[$name]?? $defaultValue;
}

/**
* 获取get参数
* @param null $name
* @param null $defaultValue
* @return |null
*/
public function get($name = null, $defaultValue = null)
{
if ($name === null) {
return $this->getQueryParams();
}
return $this->getQueryParam($name, $defaultValue);
}

public function getQueryParam($name, $defaultValue = null)
{
$params = $this->getQueryParams();
return isset($params[$name]) ? $params[$name] : $defaultValue;
}

public function getQueryParams()
{
if (empty($this->queryParams)) {
return $this->queryParams = $_GET;
}
return $this->queryParams;
}

/**
* 获取post参数
* @param null $name
* @param null $defaultValue
* @return array|mixed|null
*/
public function post($name = null, $defaultValue = null)
{
if ($name === null) {
return $this->getBodyParams();
}
return $this->getBodyParam($name, $defaultValue);
}

public function getBodyParam($name, $defaultValue = null)
{
$params = $this->getBodyParams();
if (is_object($params)) {
try {
return $params->{$name};
} catch (\Exception $e) {
return $defaultValue;
}
}
return isset($params[$name]) ? $params[$name] : $defaultValue;
}

public function getBodyParams()
{
$contentType = strtolower($this->getHeader('Content-Type'));
if ($contentType == 'multipart/form-data') {
$this->bodyParams = $_POST;
} else {
$this->bodyParams = \json_decode(file_get_contents("php://input"), true);
}
return $this->bodyParams?? [];
}

/**
* get参数数组
*/
private $queryParams = [];

/**
* post参数数组
*/
private $bodyParams = [];

private $method;
}


知识点:

  1. 获取请求头部信息的方式nginx和apache不同
  • apache可以使用apache_request_headers
  • nginx使用$_SERVER,并且需要注意的是的是自定义信息等参数会在前面自动加上http_,并且会转换为大写

server图片

  1. post参数获取的方式
  • 当Content-Type是application/x-www-data-urlencodedmultipart/form-data时,数据会放进$_POST中;
  • 除了Coentent-Type为multipart/form-data的情况,数据都可以通过file_get_contents(“php://input”)取到;
  • 不建议使用$GLOBALS[‘HTTP_RAW_POST_DATA’]

Response

Response默认以使用广泛的json输出,暂时也只考虑json格式输出的情况。

<?php
/**
* 数据输出
*/

namespace Library\Https;

use Library\Components\Base;

class Response extends Base
{
public $code = 0;

public $result = [];

public $msg = "success";

public function send()
{
header('Content-Type:application/json; charset=utf-8');
echo \json_encode([
'data' => $this->result,
'msg' => $this->msg,
'code' => $this->code,
'timestamp' => time()
]);
}

public function json($data = [])
{
$this->result = array_merge($this->result, $data);
return $this;
}
}

知识点:

  1. header() 用于发送原生的 HTTP 头。
  2. json_encode ( mixed $value [, int $options = 0 [, int $depth = 512 ]] ) : string — 对变量进行 JSON 编码,options可以预定义常量,如 JSON_UNESCAPED_UNICODE,JSON_UNESCAPED_SLASHES。

Controller

结合输出对象,我们在创建一个基类控制器,也放在相同的Https目录,我们控制创建一个构造函数,实例化一个Response,并实现一个通用的json:

<?php
/**
* 基类控制器
* 预定义json方法,便于其他控制器使用
* 返回格式
{
"data": [],
"msg": "success",
"code": 0,
"timestamp": 1572231957
}
*/

namespace Library\Https;

class Controller
{
protected $response;

protected $code = 200;

public function __construct()
{
$this->response = new Response();
}

public function json($data = [])
{
return $this->response->json($data);
}

public function index($params)
{
return $this->response->json(['hello' => 'saif']);
}
}

app应用里的控制器都必须继承这个基类控制器。