简体   繁体   English

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

[英]PHP/OOP - Using parent class to run child functions

I'm looking for a way to have a single base class that can be extended by several child classes, only one of which would be active at a time. 我正在寻找一种可以将单个子类扩展为多个子类的方法,一次只能选择其中一个子类。 A very basic example: 一个非常基本的例子:

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
    }

}

Each child initializes itself and registers as an option for the user to select. 每个孩子都会初始化自己并注册为选项供用户选择。 After the user has chosen which integration to use, this is saved to the database. 用户选择了要使用的集成后,它将保存到数据库中。 I'd like future access to the API_Base to look something like: 我希望以后访问API_Base类似于:

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

So when $api->add_contact() is run, it only runs the add_contact() function for the active API integration. 因此,运行$api->add_contact() ,它仅运行add_contact()函数以进行活动的API集成。

Eventually I'd like to somehow use get_class_methods(); 最终我想以某种方式使用get_class_methods(); to return the capabilities of just the active API, so functions accessing the API can know what is possible (ie some API's support email lists while others don't, or support creating custom fields, etc.). 返回仅活动API的功能,因此访问API的功能可以知道可能的情况(即某些API支持电子邮件列表,而其他API不支持,或支持创建自定义字段等)。

I've had some success with calling parent::set_context($context); 我通过调用parent::set_context($context);获得了一些成功parent::set_context($context); from the enabled class, but I still can't figure out how to get the parent to only execute the methods in the "enabled" child class. 从启用的类中,但我仍然不知道如何让父级仅执行“已启用”子类中的方法。

This is not how inheritance works. 继承不是这样工作的。 Child subclasses inherit from their parent class. 子子类从其父类继承。

To solve your problem you can add a factory method to API_Base which will create API implementation by its type: 为了解决您的问题,您可以向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
}

and use it like this: 并像这样使用它:

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

You can consider Abstract Class Implementation . 您可以考虑抽象类实现。 The abstract class works as the , who ever is extending the abstract class can execute the methods it have . 抽象类的作用是,扩展抽象类的人可以执行它拥有的方法。

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" ;
      }

    }

I got it working in a way works perfectly for me, thanks to Ihor's advice. 多亏了Ihor的建议,我的工作方式对我来说非常完美。 Here's what I ended up doing: 我最终要做的是:

In the main plugin file, there's a filterable function where other devs can add new integrations if they need. 在主插件文件中,有一个可过滤的功能,其他开发人员可以在需要时添加新的集成。 The first parameter is the slug (for my autoloader) and the second is the class name. 第一个参数是slug(对于我的自动装带器),第二个参数是类名。

public function get_apis() {

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

}

Each integration contains the slug and the class name. 每个集成都包含段和类名。 Then in my API_Base class I have this in the constructor: 然后在我的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;
                }

            }

        }

    }
}

And in my main file, after all the includes, I run: 然后,在我的主文件中,运行所有包含项:

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

Now I can call self::$instance->api->add_contact($email); 现在我可以叫self::$instance->api->add_contact($email); and it will trigger whichever is the current active API. 它将触发当前活动的API中的任何一个。

It seems to be the best approach as this way I can spin up the API only once when the plugin loads, instead of having to create a new instance each time I want to use it. 这似乎是最好的方法,因为这样一来,插件加载时我只能旋转一次API,而不必每次使用时都必须创建一个新实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM