colly_wyx
2018-06-14 bef2c06923d3ba6727654f734bb93d5a09855dc5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
<?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']);
    }
}