【问题标题】:PHP Return Static ClassPHP 返回静态类
【发布时间】:2013-10-30 13:14:40
【问题描述】:

我正在为micro-framework I've been working on 构建一个插件接口,并试图解决一个概念性问题。我决定制作的第一个“插件”是 Stripe 集成,本质上是采用 Stripe 的 PHP 库并将其包装为插件。我有一种工厂模式,它允许检索插件实例,例如:

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

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

Stripe::setApiKey('xyz');

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

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

在控制器中使用插件

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

在插件中

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

我不确定这样的方法是否可行,即使可行,如果这是最好的方法。

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

【问题讨论】:

    标签: php oop instance static-methods


    【解决方案1】:

    __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(),而您作为框架作者可以开发享受非静态架构的好处。你未来的自己和你的用户会为此感谢你的。

    【讨论】:

    • 对,所有插件都实现了Plugin 抽象。目标是抽象 static 调用,就用户所知,他们只需调用实例上的方法即可。
    • 这真是个好主意,乔恩,感谢您的架构建议!我意识到有无数的 PHP 框架,我只是将这个项目用作练习完整实现的一种方式。
    猜你喜欢
    • 1970-01-01
    • 2011-09-09
    • 2022-01-27
    • 2015-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-20
    • 1970-01-01
    相关资源
    最近更新 更多