论WordPress的单例模式,和更好的初始化方法
WordPress中,插件使用单例模式,性能更好,免得资源浪费。
平时,以面向对象的写法是这样的:
class Plugin
{
/**
* Constructor.
*/
public function __construct()
{
// Actions
add_action('wp_enqueue_scripts', array($this, 'enqueue_script'));
// Filters
add_filter('the_content', array($this, 'the_content'));
}
/**
* 一些方法
*/
public function enqueue_script()
{
// ...
}
}
$plugin = new Plugin();
或者,其他流行的方法是实例化一个对象类。在外部,使用该实例注册你的动作和过滤器。
class Plugin
{
public function enqueue_script()
{
// ...
}
public function the_content($content)
{
// ...
return $content;
}
}
$plugin = new WP_Kickass_Plugin();
// Actions
add_action('wp_enqueue_scripts', array($plugin, 'enqueue_script'));
// Filters
add_filter('the_content', array($plugin, 'the_content'));
这两种方法都有一个问题,那就是没有一种简单的方法可以在之后将该对象取回,容易被覆盖。当然了,名字可以尽量起得不一样。
实际上,WordPress同样可以使用单例模式,实现单例模式的类有三个元素。你必须:
- 有一个私有静态变量来存储实例化的对象。
- 将构造函数设为私有。
- 创建一个公共静态方法(通常称为“get_instance”)来获取实例化的对象。
看一下前面的两个例子。可以按照上述步骤将它们转换为单例。生成的代码与原始代码非常接近。第一个示例使用构造函数注册所有操作和过滤器,可以在下面看到转换后的代码。
class Plugin
{
private static $instance;
public static function get_instance()
{
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor.
*/
private function __construct()
{
// Actions
add_action('wp_enqueue_scripts', array($this, 'enqueue_script'));
// Filters
add_filter('the_content', array($this, 'the_content'));
}
/**
*加载其他功能
*/
public function enqueue_script()
{
// ...
}
public function the_content($content)
{
// ...
return $content;
}
}
$plugin = Plugin::get_instance();
将其转换为单例需要进行一些更改。将构造函数设为私有,并添加了静态变量和“get_instance”方法,结果与前面的示例几乎相同。
同样,可以放到外面来调用:
class Plugin
{
private static $instance;
public static function get_instance()
{
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor.
*/
private function __construct()
{
// So ronery...
}
public function the_content($content)
{
// ...
return $content;
}
}
// Actions
add_action('wp_enqueue_scripts', array(Plugin::get_instance(), 'enqueue_script'));
// Filters
add_filter('the_content', array(Plugin::get_instance(), 'the_content'));
我们需要创建一个空的私有构造函数。这是因为默认情况下构造函数是公共的。私有构造函数的另一个副作用是我们不能使用new关键字创建对象。我们需要通过调用“get_instance”将其传递给寄存器函数。值得注意的是,单例使第二种方法的吸引力大大降低。如果在构造函数中注册钩子,那么单例模式更有趣。
从构造函数中初始化插件
构造函数的作用是准备对象以供使用,用插件API注册操作和过滤器根本不适合这个任务。使用静态方法创建对象并在那里注册所有内容显然更好。
class Plugin
{
/**
* 注册插件
*/
public static function register()
{
$plugin = new self();
// Actions
add_action('wp_enqueue_scripts', array($plugin, 'enqueue_script'));
// Filters
add_filter('the_content', array($plugin, 'the_content'));
}
public function __construct()
{
// Setup your plugin object here
}
public function enqueue_script()
{
// ...
}
}
Plugin::register();
这使WordPress代码更加解耦。唯一的问题是,一旦对象注册,就不能更改它。
构造函数现在也是公共的,没有必要私有了。这意味着实例化一个新对象对WordPress不再有任何影响。
这些变化还有另一个积极的好处。可以进行类单元可测试。
将插件API拆分为自己的类,这是克服使用单例模式的更高级的方法,其思想是将插件API的使用与所有类分离。创建一个类,该类的唯一责任是与之交互。
这就是我在编写使用接口的示例时想到的,创建该类就不需要在其他类中使用“add_action”和“add_filter”。我们在这里使用插件API,但是对于插件中非常依赖的任何API,都应该这样做。
关于单例模式值得了解,也就是说,使用它是一种选择,你不必这么做。对于你来说,有各种各样的方法来回避单例模式解决的问题。