1

我正在为我一直在研究的微框架构建一个插件接口,并试图解决一个概念问题。我决定制作的第一个“插件”是 Stripe 集成,本质上是采用 Stripe 的 PHP 库并将其包装为插件。我有一种工厂模式,它允许检索插件实例,例如:

$stripe = Iceberg::getPlugin('Stripe');

如果可以实例化一个类就足够简单了,但是对于 Stripe 库,所有类都是static。在他们的例子中,他们建议做一个include()主 Stripe 文件,然后你可以像这样使用它:

Stripe::setApiKey('xyz');

我的断开连接是如何使我的getPlugin()方法与只公开静态接口的类一起工作。我显然无法实例化该类并期望它正常工作,但同时,我希望此方法能够工作,而不管实例或静态对象如何。

我的一个想法是在我的 Stripe Plugin 类中实现一个__call()方法,然后尝试将这些调用静态传递给 Stripe 库,例如:

在控制器中使用插件

$stripe = Iceberg::getPlugin('Stripe');
$stripe->setApiKey('xyz');

在插件中

public function __call( $name, $arguments ) 
{
    Stripe::$name($arguments);
}

我不确定这样的事情是否会起作用,即使会,如果那是最好的方法。

TLDR:我如何创建一个可以与对象上下文和静态上下文中的类交互的对象?

4

1 回答 1

2

__call只要您正确转发参数,转发应该可以工作:

public function __call($name, $arguments) 
{
    return call_user_func_array(['Stripe', $name], $arguments);
}

一般来说,这可能是有问题的,因为您的插件看起来像是基于实例的,而实际上并非如此(状态在所有实例之间共享,因为它static在幕后)。在您的情况下,这可能不是真正的问题,因为Iceberg::getPlugin可能记录了每次为每个不同的插件名称返回相同的实例。

也就是说,您的问题源于这样一个事实,即 Stripe 库作者犯了使库静态化的新手错误,这导致了各种问题(共享状态,难以模拟库以进行单元测试)。

不要自己犯同样的错误:Iceberg. 如果有人想要超方便地访问您的服务,他们总是可以这样做:

function Iceberg() {
    static $instance;
    if ($instance === null) $instance = new Iceberg();
    return $instance;
}

他们现在Iceberg()->foo()可以像Iceberg::foo()以前一样编写,而您作为框架作者可以开发享受非静态架构的好处。你未来的自己和你的用户会为此感谢你。

于 2013-10-30T13:20:26.237 回答