| <?php | 
| /** | 
|  * PhalApi客户端SDK包(PHP版) | 
|  * | 
|  * - 以接口查询语言(ASQL)的方式来实现接口请求 | 
|  * - 出于简明客户端,将全部的类都归于同一个文件,避免过多的加载 | 
|  *  | 
|  * <br>使用示例:<br> | 
|  ``` | 
|  * $rs = PhalApiClient::create() | 
|  *   ->withHost('http://demo.phalapi.net/') | 
|  *   ->withService('Default.Index') | 
|  *   ->withParams('name', 'dogstar') | 
|  *   ->withTimeout(3000) | 
|  *   ->request(); | 
|  * | 
|  * var_dump($rs->getRet(), $rs->getData(), $rs->getMsg()); | 
| ``` | 
|     * | 
|     * @package     PhalApi\SDK | 
|     * @license     http://www.phalapi.net/license GPL 协议 | 
|     * @link        http://www.phalapi.net/ | 
|     * @author      dogstar <chanzonghuang@gmail.com> 2015-10-16 | 
|  */ | 
|   | 
| class PhalApiClient { | 
|   | 
|     protected $host; | 
|     protected $filter; | 
|     protected $parser; | 
|     protected $service; | 
|     protected $timeoutMs; | 
|     protected $params = array(); | 
|   | 
|     /** | 
|      * 创建一个接口实例,注意:不是单例模式 | 
|      * @return PhalApiClient | 
|      */ | 
|     public static function create() { | 
|         return new self(); | 
|     } | 
|   | 
|     protected function __construct() { | 
|         $this->host = ""; | 
|   | 
|         $this->parser = new PhalApiClientParserJson(); | 
|     } | 
|   | 
|     /** | 
|      * 设置接口域名 | 
|      * @param string $host | 
|      * @return PhalApiClient | 
|      */ | 
|     public function withHost($host) { | 
|         $this->host = $host; | 
|         return $this; | 
|     } | 
|   | 
|     /** | 
|      * 设置过滤器,与服务器的DI()->filter对应 | 
|      * @param PhalApiClientFilter $filter 过滤器 | 
|      * @return PhalApiClient | 
|      */ | 
|     public function withFilter(PhalApiClientFilter $filter) { | 
|         $this->filter = $filter; | 
|         return $this; | 
|     } | 
|   | 
|     /** | 
|      * 设置结果解析器,仅当不是JSON返回格式时才需要设置 | 
|      * @param PhalApiClientParser $parser 结果解析器 | 
|      * @return PhalApiClient | 
|      */ | 
|     public function withParser(PhalApiClientParser $parser) { | 
|         $this->parser = $parser; | 
|         return $this; | 
|     } | 
|   | 
|     /** | 
|      * 重置,将接口服务名称、接口参数、请求超时进行重置,便于重复请求 | 
|      * @return PhalApiClient | 
|      */ | 
|     public function reset() { | 
|         $this->service = ""; | 
|         $this->timeoutMs = 3000; | 
|         $this->params = array(); | 
|   | 
|         return $this; | 
|     } | 
|   | 
|     /** | 
|      * 设置将在调用的接口服务名称,如:Default.Index | 
|      * @param string $service 接口服务名称 | 
|      * @return PhalApiClient | 
|      */ | 
|     public function withService($service) { | 
|         $this->service = $service; | 
|         return $this; | 
|     } | 
|   | 
|     /** | 
|      * 设置接口参数,此方法是唯一一个可以多次调用并累加参数的操作 | 
|      * @param string $name 参数名字 | 
|      * @param string $value 值 | 
|      * @return PhalApiClient | 
|      */ | 
|     public function withParams($name, $value) { | 
|         $this->params[$name] = $value; | 
|         return $this; | 
|     } | 
|   | 
|     /** | 
|      * 设置超时时间,单位毫秒 | 
|      * @param int $timeoutMs 超时时间,单位毫秒 | 
|      * @return PhalApiClient | 
|      */ | 
|     public function withTimeout($timeoutMs) { | 
|         $this->timeoutMs = $timeoutMs; | 
|         return $this; | 
|     } | 
|   | 
|     /** | 
|      * 发起接口请求 | 
|      * @return PhalApiClientResponse | 
|      */ | 
|     public function request() { | 
|         $url = $this->host; | 
|   | 
|         if (!empty($this->service)) { | 
|             $url .= '?service=' . $this->service; | 
|         } | 
|         if ($this->filter !== null) { | 
|             $this->filter->filter($this->service, $this->params); | 
|         } | 
|   | 
|         $rs = $this->doRequest($url, $this->params, $this->timeoutMs); | 
|   | 
|         return $this->parser->parse($rs); | 
|     } | 
|   | 
|     protected function doRequest($url, $data, $timeoutMs = 3000) | 
|     { | 
|         $ch = curl_init(); | 
|   | 
|         curl_setopt($ch, CURLOPT_URL, $url); | 
|         curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | 
|         curl_setopt($ch, CURLOPT_HEADER, 0); | 
|         curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, $timeoutMs); | 
|   | 
|         if (!empty($data)) { | 
|             curl_setopt($ch, CURLOPT_POST, 1); | 
|             curl_setopt($ch, CURLOPT_POSTFIELDS, $data); | 
|         } | 
|   | 
|         $rs = curl_exec($ch); | 
|   | 
|         curl_close($ch); | 
|   | 
|         return $rs; | 
|     } | 
| } | 
|   | 
| /** | 
|  * 接口返回结果 | 
|  * | 
|  * - 与接口返回的格式对应,即有:ret/data/msg | 
|  */ | 
| class PhalApiClientResponse { | 
|   | 
|     protected $ret = 200; | 
|     protected $data = array(); | 
|     protected $msg = ''; | 
|   | 
|     public function __construct($ret, $data = array(), $msg = '') { | 
|         $this->ret = $ret; | 
|         $this->data = $data; | 
|         $this->msg = $msg; | 
|     } | 
|   | 
|     public function getRet() { | 
|         return $this->ret; | 
|     } | 
|   | 
|     public function getData() { | 
|         return $this->data; | 
|     } | 
|   | 
|     public function getMsg() { | 
|         return $this->msg; | 
|     } | 
| } | 
|   | 
| /** | 
|  * 接口过滤器 | 
|  *  | 
|  * - 可用于接口签名生成 | 
|  */ | 
| interface PhalApiClientFilter { | 
|   | 
|     /** | 
|      * 过滤操作 | 
|      * @param string $service 接口服务名称 | 
|      * @param array $params 接口参数,注意是引用。可以直接修改 | 
|      * @return null | 
|      */ | 
|     public function filter($service, array &$params); | 
| } | 
|   | 
| /** | 
|  * 接口结果解析器 | 
|  *  | 
|  * - 可用于不同接口返回格式的处理 | 
|  */ | 
| interface PhalApiClientParser { | 
|   | 
|     /** | 
|      * 结果解析 | 
|      * @param string $apiResult | 
|      * @return PhalApiClientResponse | 
|      */ | 
|     public function parse($apiResult); | 
| } | 
|   | 
| /** | 
|  * JSON解析 | 
|  */ | 
| class PhalApiClientParserJson implements PhalApiClientParser { | 
|   | 
|     public function parse($apiResult) { | 
|         if ($apiResult === false) { | 
|             return new PhalApiClientResponse(408, array(), 'Request Timeout'); | 
|         } | 
|   | 
|         $arr = json_decode($apiResult, true); | 
|   | 
|         if ($arr === false || empty($arr)) { | 
|             return new PhalApiClientResponse(500, array(), 'Internal Server Error'); | 
|         } | 
|   | 
|         return new PhalApiClientResponse($arr['ret'], $arr['data'], $arr['msg']); | 
|     } | 
| } |