PHP返回静态类

时间:2013-10-30 13:14:41

标签: php oop instance static-methods

我正在构建一个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:如何在对象上下文和静态上下文中创建可与类进行交互的对象?

1 个答案:

答案 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(),并且您作为框架作者可以开发享受非静态架构的好处。您未来的自我和您的用户将会感谢您。