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; }
知识点:
获取请求头部信息的方式nginx和apache不同
apache可以使用apache_request_headers
nginx使用$_SERVER,并且需要注意的是的是自定义信息等参数会在前面自动加上http_,并且会转换为大写
post参数获取的方式
当Content-Type是application/x-www-data-urlencoded
或multipart/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; } }
知识点:
header() 用于发送原生的 HTTP 头。
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应用里的控制器都必须继承这个基类控制器。