设计PHP API包装器

时间:2013-03-04 23:37:41

标签: php frameworks wrapper

我想知道将两个similair API实现到一个PHP框架中的好方法是什么?

我的想法是这样的:

  • /vendors/wrapperA.php - 扩展Parent,实现API (A)
  • /vendors/wrapperB.php - 扩展Parent,实现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是哪个?
  4. 编辑:根据马林的答案设计的解决方案

    <?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');
    

2 个答案:

答案 0 :(得分: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;
    }
}  

答案 1 :(得分:0)

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

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

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

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