PHP / OOP - 使用父类来运行子函数

时间:2015-12-25 16:55:10

标签: php oop

我正在寻找一种方法来拥有一个可以由多个子类扩展的基类,其中只有一个子类可以一次处于活动状态。一个非常基本的例子:

class API_Base {

    public $context;

    public function __construct() {
        $this->init()
    }
}

class Mailchimp_API extends API_Base {

    public function init() {
        $this->context = 'mailchimp';
        $this->enabled = false; 
    }

    public function add_contact($email_address) {
        // mailchimp API for adding contact
    }
}

class Infusionsoft_API extends API_Base {

    public function init() {
        $this->context = 'infusionsoft';
        $this->enabled = true;
    }

    public function add_contact($email_address) {
        // infusionsoft API for adding contact
    }

}

每个孩子初始化自己并注册为用户选择的选项。在用户选择要使用的集成之后,将其保存到数据库中。我希望将来访问API_Base看起来像:

$api = new API_Base();
$api->context; // should be "infusionsoft"
$api->add_contact($email_address);

因此,当$api->add_contact()运行时,它只运行add_contact()函数来进行活动API集成。

最终我想以某种方式使用get_class_methods();来返回活动API的功能,因此访问API的函数可以知道什么是可能的(即一些API的支持电子邮件列表,而其他人没有,或者支持创建自定义字段等。)。

我从启用的类中调用parent::set_context($context);取得了一些成功,但我仍然无法弄清楚如何让父进程只执行“enabled”子类中的方法。

3 个答案:

答案 0 :(得分:2)

这不是继承的工作原理。子类继承自其父类。

要解决您的问题,您可以向API_Base添加工厂方法,该方法将按类型创建API实现:

class API_Base {
    public static function createByType($type)
    {
        switch ($type) {
            case 'mailchimp': return new Mailchimp_API();
            case 'infusionsoft': return new Infusionsoft_API();
            default: throw new \InvalidArgumentException(spintf('Invalid API type "%s"', $type));
        } 
    }
    // other methods
}

并像这样使用它:

$api = API_Base::createByType($user->selectedApi);
$api->context; // should be "infusionsoft"
$api->add_contact($email_address);

答案 1 :(得分:0)

您可以考虑抽象类实现。抽象类的工作原理是,扩展抽象类的人可以执行它拥有的方法。

abstract class Something{
       function __construct(){
        // some stuff
       }

       function my_func(){
         $this->myTest ;
       }

      abstract function my_func(); 

      }

    class Some extends Something{

      function __construct(){
        parent::__construct() ;
      }

      function my_test(){
           echo "Voila" ;
      }

    }

答案 2 :(得分:0)

感谢Ihor的建议,我让它以适合我的方式工作。这就是我最终做的事情:

在主插件文件中,有一个可过滤的功能,其他开发人员可以根据需要添加新的集成。第一个参数是slug(对于我的自动加载器),第二个参数是类名。

public function get_apis() {

    return apply_filters( 'custom_apis', array(
        'infusionsoft-isdk'         => 'MYPLUGIN_Infusionsoft_iSDK',
        'infusionsoft-oauth'        => 'MYPLUGIN_Infusionsoft_oAuth',
        'activecampaign'            => 'MYPLUGIN_ActiveCampaign'
    ) );

}

每个集成都包含slug和类名。然后在我的API_Base类中,我在构造函数中有这个:

class API_Base {

    public $available_apis = array();

    public $api;

    public function __construct() {

        $configured_apis = main_plugin()->get_apis();

        foreach( $configured_apis as $slug => $classname ) {

            if(class_exists($classname)) {

                $api = new $classname();
                $api->init();

                if($api->active == true)
                    $this->api = $api;

                $this->available_apis[$slug] = array( 'name' => $api->name );

                if(isset($api->menu_name)) {
                    $this->available_apis[$slug]['menu_name'] = $api->menu_name;
                } else {
                    $this->available_apis[$slug]['menu_name'] = $api->name;
                }

            }

        }

    }
}

在我的主文件中,在所有包含之后,我运行:

self::$instance->api_base       = new API_Base();
self::$instance->api            = self::$instance->api_base->api;

现在我可以调用self::$instance->api->add_contact($email);,它将触发当前活动API中的任何一个。

这似乎是最好的方法,因为这样我只能在加载插件时启动API一次,而不是每次我想要使用它时都必须创建一个新实例。

相关问题