【问题标题】:Designing a PHP API wrapper设计一个 PHP API 包装器
【发布时间】:2013-03-04 23:37:41
【问题描述】:

我想知道在一个 PHP 框架中实现两个类似 API 的好方法是什么?

我的想法是这样的:

  • /vendors/wrapperA.php - 扩展父级,实现 API (A)
  • /vendors/wrapperB.php - 扩展父级,实现 API (B)
  • Parent.php - 唯一直接引用的脚本以使用 API 包装器
  • $config[] 数组用于 Parent.php 中的配置
  • index.php - 一个实现并且仅引用 Parent.php 的网站

假设 API 有很多方法,但我们只实现了两个简单的 API 调用:

  • connect() - 创建到服务的连接。
  • put() - 如果成功则返回一个“putID”。

由于 API (A) 和 API (B) 不同,这就是包装器通过抽象这两种方法来实现其实用程序的方式。

现在,我想说的是:

  • 在 PHP 中实现此功能的好方法是什么?
  • connect() 语句需要验证是否存在有效连接。
  • put() 语句需要返回一个 ID
  • 我们不想暴露 put 方法中的差异,它只需要根据我们是否正确配置 API 身份验证(无论是什么情况 - 通过密钥或其他方式)来工作

类似

<?php $parent = new Parent();
$parent->connect(); //connect to one or both API's.
$parent->put('foo'); //push foo to the API
?>

目前,我的所有代码都在 Parent.php 中。

在 Parent.php 中包含所有代码的问题

  1. 代码蔓延
  2. 缺少模块化插件,以防我添加第三个 API。
  3. 代码混淆 - 哪个 API 是哪个?

编辑:根据 Marin 的回答设计的解决方案

<?php 

/*** Interface ***/

interface API_Wrapper {
    function connect();
    function put($file);
} 

/*** API Wrappers ***/
class API_A_Wrapper implements API_Wrapper {
    function connect() {}
    function put($file) { print 'putting to API A.'; }
}

class API_B_Wrapper implements API_Wrapper {
    function connect() {}
    function put($file) { print 'putting to API B.'; }
}

/*** Factory ***/
class Factory {
  public static function create($type){ 
    switch ($type) {
      case "API_A" : 
        $obj = new API_A_Wrapper(); 
      break;
      case "API_B" :
        $obj = new API_B_Wrapper();  
      break;
    }
    return $obj;
   } 

} 

/*** Usage ***/

$wrapperA = Factory::create("API_A");
$wrapperA->put('foo');

$wrapperB = Factory::create("API_B");
$wrapperB->put('foo');

【问题讨论】:

  • 恕我直言。 Parent 应该只是一个接口,最多是一个创建 WrapperA 或 WrapperB 对象的工厂......这样,你总是知道你有哪个类,并且接口保持不变。如果您出于某种原因需要一个类,请使用装饰器模式。
  • 接口如何防止代码蔓延?我目前将我的代码放在 Parent.php 中。随着我添加更多的方法,我使用了一个 $this->framework 变量,它不会在很长时间内扩展。
  • 据我了解,您正在尝试使用一个 API 来驱动其他几个 API,即。一个 API 可以同时映射到其他几个 API 的使用。对吗?
  • 不是从本质上讲,不是。当需要可能完全不同的第三个 API 时,接口会有所帮助。如果 WrapperA 和 WrapperB 很相似,那么它们可能继承自同一个抽象类,该抽象类可以实现接口。老实说,我更关注 2 和 3,而 Parent 显然是直接调用的;)
  • @didierc 我应该澄清一下 - 更多的是一个包装两个 API 的框架。

标签: php frameworks wrapper


【解决方案1】:

使用有关系的接口,需要时单独调用:

interface Interface {
    function somefunction();
}

class Wrapper1 implements Relation {
    public function connect() {
        return;
    }
}

class Wrapper2 {
    public function action(Interface $s) {
        $textData = $s->query();
        return;
    }
}

$p = new Wrapper1();

$i = new Wrapper2();
$i->action($p);

使用工厂作为关系:

function __autoload($class)
{
    include_once($class . '.php');
}

class DBfactory
{
    public static $pDB;

    public static function factory($szType = "")
    {
    if(!is_object(self::$pDB))
    {
        switch($szType)
        {
            case 'mysql':
                self::$pDB = new DBmysql;
                break;
            case 'mssql':
                self::$pDB = new DBmssql;
                break;
            default:
                self::$pDB = new DBmysql;
                break;
        }
    }
    return self::$pDB;
    }
}  

【讨论】:

  • 嗨,马林。感谢您的回复。两个 API 都需要身份验证,所以我需要一个 connect() 方法。我不太遵循您的基本示例。看起来您的 wrapper2 实现了 wrapper1 的功能,但在我的情况下并非如此。两种 API 都大不相同。
  • 你需要在类内部使用工厂模式来共享使用类。将函数放入Wrapper 并调用共享类的工厂模式。看这个例子:stackoverflow.com/questions/3536507/…
  • 谢谢,马林。我已经用这种方法更新了我的问题。
【解决方案2】:

您需要的是依赖注入。您有 2 个类 - 您称它们为包装器 - 每个类都涵盖不同的 API,但必须符合相同的接口。在您的网站中,您希望交替使用任一类,实际上使用任何底层 API 而不会影响代码库的其余部分,因此是常见的Parent 接口。

但是,在某些时候,您的代码将不得不决定将使用哪个包装器,并且如果您想包含新的 Parent 实现,您担心必须在您的代码库中手动包含这些新的包装器。

这个问题通过依赖注入来解决。这个想法是有一个专用的对象 - 一个工厂 - 封装可用包装器的所有细节,并且任何需要当下包装器的代码都可以向该工厂询问它。显然,您的代码只需处理 Parent 接口的工厂和实例。

对于工厂如何决定实例化哪个包装器是您的选择。许多人使用包含哪个类必须与代码的哪个部分一起使用的配置文件。这可以通过使用与包装器客户端关联的 id(即使用它们的代码)来实现,并且客户端在请求包装器时会给工厂这个 id。然后,工厂只需查找 id 并提供一个 ad-hoc 实例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-26
    • 2015-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-28
    • 2016-06-23
    • 1970-01-01
    相关资源
    最近更新 更多