我正在构建一个micro-framework I've been working on的插件界面,我正在努力解决一个概念性问题。我决定制作的第一个“插件”是Stripe集成,基本上将Stripe的PHP库包装起来并将其包装为插件。我有一种工厂模式,它允许检索插件实例,如:
$stripe = Iceberg::getPlugin('Stripe');
在可以实例化类的情况下足够简单,但对于Stripe库,所有类都是 static 。在他们的示例中,他们建议执行主要Stripe文件的include()
,然后您可以像以下一样使用它:
Stripe::setApiKey('xyz');
我的断开连接是如何让我的getPlugin()
方法使用只暴露静态接口的类。我显然无法实例化该类并期望它能够正常工作,但与此同时,无论实例还是静态对象,我都希望这种方法能够正常工作。
我有一个想法是在我的Stripe Plugin类中实现__call()
方法,然后尝试静态地将这些调用传递给Stripe库,如:
使用插件的控制器
$stripe = Iceberg::getPlugin('Stripe');
$stripe->setApiKey('xyz');
插件
public function __call( $name, $arguments )
{
Stripe::$name($arguments);
}
我不确定这样的东西是否会起作用,即使这样,如果这样做是最好的方式。
TLDR:如何在对象上下文和静态上下文中创建可与类进行交互的对象?
答案 0 :(得分:2)
__call
转发应该有效,只要您正确转发参数:
public function __call($name, $arguments)
{
return call_user_func_array(['Stripe', $name], $arguments);
}
一般情况下,这可能会有问题,因为您的插件看起来像是基于实例的,而实际上它不是(状态在所有实例之间共享,因为它在幕后是static
)。在您的情况下可能不是真正的问题,因为Iceberg::getPlugin
可能记录为每次为每个不同的插件名称返回相同的实例。
那就是说,你的问题源于这样一个事实:Stripe库的作者犯了新的错误,使得库变得静态,导致各种问题(共享状态,难以模拟库进行单元测试)。 / p>
不要自己犯同样的错误:从Iceberg
中丢失所有公共静态成员。如果有人想要非常方便地访问您的服务,他们总是可以这样做:
function Iceberg() {
static $instance;
if ($instance === null) $instance = new Iceberg();
return $instance;
}
他们现在可以像编写Iceberg()->foo()
一样编写Iceberg::foo()
,并且您作为框架作者可以开发享受非静态架构的好处。您未来的自我和您的用户将会感谢您。