我正在寻找一种方法来拥有一个可以由多个子类扩展的基类,其中只有一个子类可以一次处于活动状态。一个非常基本的例子:
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”子类中的方法。
答案 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一次,而不是每次我想要使用它时都必须创建一个新实例。