简体   繁体   English

PHP返回静态类

[英]PHP Return Static Class

I'm building a plugin interface to a micro-framework I've been working on and am trying to work through a conceptual problem. 我正在为我一直在研究微框架构建一个插件界面,并试图解决一个概念性问题。 The first "plugin" I've decided to make is a Stripe integration, essentially taking the PHP library for Stripe and wrapping it as a Plugin. 我决定制作的第一个“插件”是Stripe集成,本质上是将Stripe的PHP库用作包装。 I have a sort of factory pattern which allows retrieval of plugin instances like: 我有一种工厂模式 ,它允许检索插件实例,例如:

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

Simple enough in the event that a class can be instantiated, but for the Stripe library, all of the classes are static . 在可以实例化一个类的情况下非常简单,但是对于Stripe库,所有类都是static In their examples, they recommend doing an include() of the main Stripe file, and then you can use it like: 在他们的示例中,他们建议对主Stripe文件执行include() ,然后可以像下面这样使用它:

Stripe::setApiKey('xyz');

My disconnect is how I can make my getPlugin() method work with classes that only expose static interfaces. 我断开连接的方法是如何使getPlugin()方法与仅公开静态接口的类一起使用。 I obviously cannot instantiate the class and expect it to work correctly, but at the same time, I want this method to work regardless of instance or static objects. 我显然不能实例化该类并期望它能够正常工作,但是与此同时,我希望此方法不管实例还是静态对象都可以工作。

One idea I've had is to implement a __call() method in my Stripe Plugin class, and then try to pass those calls to the Stripe library statically, like: 我曾经有一个想法是在我的Stripe插件类中实现__call()方法,然后尝试将这些调用静态传递给Stripe库,例如:

In Controller using Plugin 在控制器中使用插件

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

In Plugin 在插件中

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

I'm not sure if something like that would even work, and even if it would, if that would be the best way. 我不确定类似的方法是否会奏效,即使可行,这是否是最佳方法。

TLDR: How can I create an object that can interface with classes in both object contexts and static contexts? TLDR:如何创建可以在对象上下文和静态上下文中与类交互的对象?

The __call forwarding should work, as long as you forward the arguments correctly: 只要您正确转发参数, __call转发就应该起作用:

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

In general this might be problematic because your plugin looks like it is instance-based, when in reality it is not (state is shared among all instances because it's static behind the scenes). 通常,这可能会带来问题,因为您的插件看起来像是基于实例的,而实际上却并非基于实例(状态在所有实例之间共享,因为它在后台是static的)。 In your case that might not really be an issue as Iceberg::getPlugin is probably documented to return the same instance every time for each distinct plugin name. 在您的情况下,这可能并不是真正的问题,因为Iceberg::getPlugin可能被记录为每次为每个不同的插件名称返回相同的实例。

That said, your problem here stems from the fact that the Stripe library authors made the rookie mistake of making the library static, which leads to all kinds of problems (shared state, hard to mock the library for unit testing). 就是说,您的问题来自于这样一个事实:Stripe库作者犯了使库静态化的新手错误,这会导致各种问题(共享状态,难以模拟用于单元测试的库)。

Don't make the same mistake yourself: lose all public static members from Iceberg . 不要自己犯同样的错误:Iceberg失去所有公共静态成员。 If someone wants ultra-convenient access to your services they can always do this: 如果有人想要超方便地访问您的服务,则可以随时执行以下操作:

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

They can now write Iceberg()->foo() just like they would write Iceberg::foo() before, and you as the framework author can develop enjoying the benefits of a non-static architecture. 现在,他们可以像以前编写Iceberg::foo()一样编写Iceberg()->foo()了,作为框架作者,您可以享受非静态体系结构带来的好处。 Your future self and your users will thank you for it. 您未来的自我和您的用户将感谢您。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM