那我贴出来吧。为什么要有 facade 等东西,目的就是为了实现 “调用方式不变,实现方式可变”啊。
```
<?php
require_once(__DIR__.'/vendor/autoload.php'); //@DUCKPHP_HEADFILE
use think\api\Client;
use GuzzleHttp\Client as GuzzleHttp_Client;
use GuzzleHttp\HandlerStack ;
use think\helper\Str;
trait SingletonExTrait
{
protected static $_instances = [];
public static function G($object = null)
{
if (defined('__SINGLETONEX_REPALACER')) {
$callback = __SINGLETONEX_REPALACER;
return ($callback)(static::class, $object);
}
//fwrite(STDOUT,"SINGLETON ". static::class ."\n");
if ($object) {
self::$_instances[static::class] = $object;
return $object;
}
$me = self::$_instances[static::class] ?? null;
if (null === $me) {
$me = new static();
self::$_instances[static::class] = $me;
}
return $me;
}
}
class MyService
{
use SingletonExTrait;
public $options =[
'endpoint' => '
https://api.topthink.com/',
'app_code' => '???',
'default_http_method'=>'GET',
];
public function init(array $options, object $context = null)
{
$this->options = array_intersect_key(array_replace_recursive($this->options, $options) ?? [], $this->options);
}
protected function do_call($method, $args)
{
$http_method = $this->get_http_method($method);
$uri = $this->get_uri($method);
$parameters = $this->get_parameters($method, $args);
try {
return $this->do_request($this->options['endpoint'], $this->options['app_code'], $http_method, $uri, $parameters);
} catch (RequestException $e) {
if ($e->hasResponse()) {
$response = $e->getResponse();
throw new Exception($response->getStatusCode(), $response->getBody()->getContents());
}
throw $e;
}
}
protected function get_http_method($method)
{
return $this->options['default_http_method'];
}
protected function get_uri($method)
{
//TODO 移除 Str 的引用
return $this->uri_map[$method] ?? Str::snake(class_basename($method), "/");
}
protected function get_parameters($method, $args)
{
$reflect = new \ReflectionMethod($this, $method);
$ret=[];
$params = $reflect->getParameters();
foreach ($args as $i => $v) {
if($v === null){
continue;
}
$name = $params[$i]->getName();
$ret[$name] = $v;
}
return $ret;
}
protected function do_request($endpoint, $app_code, $method, $uri, $parameters)
{
$body =[];
if ($method == 'GET') {
$options['query'] = $data;
} else {
$options['body'] = $data;
}
$handleStack = HandlerStack::create(null);
$client = new GuzzleHttp_Client([
'base_uri' => $endpoint,
'handler' => $handleStack,
'headers' => [
'Authorization' => "AppCode ".$app_code,
'User-Agent' => "ThinkApi/1.0",
],
'verify' => false,
]);
$response = $client->request($method, $uri, $options);
$result = $response->getBody()->getContents();
if (false !== strpos($response->getHeaderLine('Content-Type'), 'application/json')) {
$result = json_decode($result, true);
}
return $result;
}
}
// 这个类用脚本生成,省略更多
class CalendarService extends MyService
{
/**
* 查日历
*
* @
access public
* @
param mixed $year_month
*/
public function calendarMonth($yearMonth = null){
return $this->do_call(__FUNCTION__, func_get_args());
}
}
class LocalCalendarService extends CalendarService
{
public function calendarMonth($yearMonth = null){
return ['这是模拟数据'];
}
}
//*
// 这里是核心工程师老大的干活
//CalendarService::G(LocalCalendarService::G()); // 线上出问题的时候切这句
$options=['app_code'=>'???'];
CalendarService::G()->init($options);
//// 下面是小弟写
$result = CalendarService::G()->calendarMonth('2019-1');
var_dump($result);
return;
//*/
$client = new Client('???');
$result = $client->calendarMonth()->withYearMonth('2019-1')->request();
var_dump($result);
```