简体   繁体   中英

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. 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 . In their examples, they recommend doing an include() of the main Stripe file, and then you can use it like:

Stripe::setApiKey('xyz');

My disconnect is how I can make my getPlugin() method work with classes that only expose static interfaces. 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:

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?

The __call forwarding should work, as long as you forward the arguments correctly:

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). 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.

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).

Don't make the same mistake yourself: lose all public static members from 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. Your future self and your users will thank you for it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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