Problem
I’m developing a WordPress plugin using the singleton pattern with the following requirements:
- There should ever exist one instance of the plugin
- Another instance of the object should never be instantiated, created, cloned, copied etc in any way.
- The singular plugin object and its public methods and vars should be easily accessible and usable in any scope, by anything including other plugins
The last one is a given with singleton pattern, but there is one concern I have:
– __construct()
should run only once, and should never run again. The code inside __construct()
should never be reparsed and reprocessed however the singleton is instantiated.
I already tested the code and it seems to work, however the code in __construct()
was being reprocessed every time i requested the instance of the object through get_instance()
outside the plugin until I added self::$instance = $this;
at the top.
I’m wondering whether I am violating the guidelines I listed above and also if it is possible for anyone to violate them through any kind of logic or method that they put into their plugins. Also whether this code will last at least a few PHP versions into the future.
class particular_plugin {
private static $instance = null;
protected function __construct()
{
self::$instance = $this;
// Numerous initialization variables and actions here
// including calls to functions inside the class
}
public static function get_instance()
{
if (null === static::$instance) {
static::$instance = new static();
}
return static::$instance;
}
private function __clone()
{
}
private function __wakeup()
{
}
}
// Initializing the plugin here
$particular_plugin = particular_plugin::get_instance();
function particular_plugin_get()
{
// This function allows any plugin to easily retrieve this plugin object and access its public methods and vars as they exist at any given point in time
return particular_plugin::get_instance();
}
Solution
Forget everything but the instatiator, constructor and property, you don’t call new static;
you call new self()
, then it jumps into the constructor, the way I do singleton is:
class Foo
{
private static $init;
private function __construct() { }
public static function init()
{
return static::$init = (
null === static::$init ? new self() : static::$init
);
}
}
$foo = Foo::init();
This makes it so when new self()
is called, it jumps to the constructor and assigns self::$init
to really be an instance of the class