跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • PHP 如何更优雅地调用 API 接口
未分類
2021 年 2 月 6 日

PHP 如何更优雅地调用 API 接口

PHP 如何更优雅地调用 API 接口

資深大佬 : topthink 10

API 接口在各种场景中已经非常普遍使用,通常在 PHP 后台调用 API 接口,需要通过 Curl 库来自己封装,且不说各种充值门槛,还要被各种 api 接口平台的 appKey 、appSecret 之类的参数困惑,没法实现统一调用,很多小白更是被 Curl 各种配置参数弄得头大。ThinkPHP官方出品的ThinkAPI服务正是为了解决 PHP 接口调用的各种麻烦问题。

ThinkAPI统一API接口服务是由官方联合合作伙伴封装的一套接口调用服务及 SDK,旨在帮助ThinkPHP开发者更方便和更低成本调用官方及第三方的提供的各类API接口及服务,从而更好的构建开发者生态。

通过ThinkAPI提供的 SDK 功能可以以更优雅的方式来调用 API 接口,首先需要在你的项目里面安装 think-api 库(适用于任何 PHP5.6+项目,没有任何框架要求)。

composer require topthink/think-api 

然后就可以调用你需要的接口进行查询和返回数据,支持ThinkAPI所有的 API 接口,以查询身份证所属地区接口为例:

use thinkapiClient;  $client = new Client("appCode");  $result = $client->idcardIndex()     ->withCardno('身份证号码')     ->request(); 

idcardIndex方法就是调用了身份证归属地查询接口 withCardno方法则表示传入了cardno参数,如果还需要传入更多的参数则链式调用更多的方法即可,最后通过request方法进行实际调用并返回数据。通过 IDE 配合的话,你不需要自己记住任何接口方法名和参数方法名,都会有自动提示。

ThinkAPI所有的 API 调用服务必须设置appCode值(只需要注册一个账号即可获取),用于接口调用的身份认证。如需多次调用的话,建议自己在项目里面封装一个助手函数,例如:

use thinkapiClient;  /**  * API 接口调用助手函数  * @return Client  */ function api(): Client {     return new Client('yourAppCode'); }  // 调用示例 $result = api()->idcardIndex()     ->withCardno('身份证号码')     ->request(); 

所有的接口服务和方法都支持 IDE 自动提示和完成(请务必注意方法大小写必须保持一致),所有的返回数据都是 JSON 格式,因此基本上不需要文档即可完成接口开发工作。API 接口调用中的一些常见问题通过系统的方法封装都可以规避掉,你甚至不需要关心接口是要用 GET 还是 POST,都是系统自动处理的。

SDK 把所有接口和参数都封装为一个个独立的方法,你可以像调用一个类的方法一样简单的调用官方支持的任何 API 接口,也无需再去记住每个接口的参数有哪些。

如果你的环境不支持 Composer 或者 PHP 版本过低,可能需要你自己封装 Curl 库来调用接口。ThinkAPI 接口文档都提供了两种方式调用:直接调用接口地址和使用 SDK 调用。

目前 ThinkAPI 已经接入包括实名认证、人工智能、电子商务、新闻资讯和生活服务等类目在内的常用 API 接口共 269 个,包含大量免费接口,付费接口的价格比较实在、门槛也低,并且还在陆续扩充中。更详细的用法可以参考: https://docs.topthink.com/think-api

大佬有話說 (23)

  • 資深大佬 : ben1024

    推荐的是付费接口,没有免费接口服务列表吗

  • 主 資深大佬 : topthink

    @ben1024 https://docs.topthink.com/think-api/1888715 这里有 标注为免费的就是免费接口

  • 資深大佬 : lepig

    这个对开发来说确实听友好的。但是奈何老板不同意。

    老板说,用付费的金接口,我要你们干啥。

  • 主 資深大佬 : topthink

    @lepig 现代化开发理念不是什么都要自己独立开发的。每个接口做自己专业的事情 因为专注才能更专业 就和组件化开发一样 接口化也是一种趋势。而且大多数接口自己没有数据没法开发的,比如身份证实名认证 只能调用第三方的。那么 ThinkAPI 的优势就是帮你简化开发 同时也能降低成本。我认为老板关注的不是用不用接口的问题 是项目什么时候能上线的问题吧~

  • 資深大佬 : Actrace

    @topthink 我觉得可能他就是那个老板

  • 資深大佬 : imgbed

    这种付费接口很多商家在做

  • 資深大佬 : lepig

    @Actrace 我还真不是。只是我们 cto 为了节约成本新申请了个阿里云账号。然后迁移所有的服务器 /oss/容器等等。然后基础运维部断断续续肝了一个多月才完成。java,php 的所有项目全部要更改配置。
    坑的一笔。
    > 我是 php 开发。

  • 資深大佬 : zpfhbyx

    PHP 如何更优雅地调用 API 接口 把自己的三方 sdk 放到你那?

  • 主 資深大佬 : topthink

    @imgbed 接口平台确实很多 但我们的优势是提供优雅的 SDK 以及更低的门槛
    @zpfhbyx 没太明白你的意思 是指接口入驻么?

  • 主 資深大佬 : topthink

    @lepig 你们这样迁移风险太大了吧 难不成每年重新申请一个账号么 哈哈

  • 資深大佬 : lepig

    @topthink 我觉得真的可能干的出来。反正今年 2/3 时间都是 996. 明年准备溜了,不管了。

  • 資深大佬 : unicloud

    看标题,以为是技术讨论。

  • 資深大佬 : zpfhbyx

    @topthink PHP 如何更优雅地调用 API 接口 额,你不就是一个各种 3 方 api 的代理么。无非就是写了一个更好用的 phpsdk 。。

  • 資深大佬 : ztxcccc

    标题和内容有什么关系吗?

  • 資深大佬 : dvaknheo

    @topthink 提供优雅的 SDK

    什么叫优雅:

    老大:想查身份证地区编码,你们这么调就够了:
    “`
    /** @var string */ $area = IdCardService::G()->idcardIndex(‘身份证号’);
    “`
    小弟:收到.

    几天后,
    小弟:报告老大 ,我们身份证地区编码得不到了
    老大:收到。现在改
    老大:打开入口代码
    “`
    // IdCardService::G(AliIdService::G());
    IdCardService::G(TencentIdService::G());
    “`
    老大:好了,已经由接入 A 家改为接入 T 家了。

    出错的时候跟踪方便。切换服务提供商方便。小弟们不需要乱动,这才叫优雅。

  • 資深大佬 : dvaknheo

    再来个优雅的:

    $client = new Client(“YourAppCode”);

    $result = $client->gstoreDisease()
    ->withSymptom(‘发烧’)
    ->request();

    老板: 免费接口,每日 100 次免费调用,会员可不限次数调用。 我们接口要烧那么多钱么?减少调用!

    老大:没问题。

    “`
    class MyService{ function gstoreDisease($Symptom ){
    // 如果我们数据库已经有,返回数据库已经存好的
    // 如果数据库没有,则请求第三方并存入数据
    }}
    小弟代码不变
    // …
    $result = MyService::G()->gstoreDisease(‘发烧’);
    “`

  • 資深大佬 : dvaknheo

    立一个 flag,我重写一个客户端,这三天内完成

  • 資深大佬 : imgbed

    @topthink tp 我是支持的,api 目前还没用到,可能后续有需求吧

  • 資深大佬 : dvaknheo

    写好了,一百五十多,放这里可能太长,又没排版 就是实现上述代码的第三方 think-api 接入类。
    有人感兴趣的话我就贴在这

  • 主 資深大佬 : topthink

    @dvaknheo 欢迎探讨 我只是说如何更优雅 我也没说是最优雅的 没必要抠字眼,至少目前我没有看到第三方的接口 SDK 有更好的
    @zpfhbyx 没错 就是通过封装一个更好用的 SDK 让接口可以更优雅的调用

  • 資深大佬 : dvaknheo

    那我贴出来吧。为什么要有 facade 等东西,目的就是为了实现 “调用方式不变,实现方式可变”啊。

    “`
    <?php
    require_once(__DIR__.’/vendor/autoload.php’); //@DUCKPHP_HEADFILE
    use thinkapiClient;
    use GuzzleHttpClient as GuzzleHttp_Client;
    use GuzzleHttpHandlerStack ;
    use thinkhelperStr;

    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);
    “`

  • 主 資深大佬 : topthink

    @dvaknheo 你这还是基于 think-api 的库 有什么优势 我还以为你要用 100 行代码写一个 think-api 出来呢,其实 think-api 库就是一个 IDE 提示工具而已 真正的调用又不是在这个库 你把问题想的太简单了吧

  • 資深大佬 : dvaknheo

    @topthink 没基于 think-api 啊, 除了用字符串处理部分还用到 thinkhelperStr 而已。 最前面的 use thinkapiClient 是后面代码切换演示方便而已。

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具