这是一个很好的问题。它深入到插件API和最佳编程实践的核心。
对于下面的答案,我创建了一个简单的插件,用易于阅读的代码来说明这个问题。
<?php # -*- coding: utf-8 -*-
/* Plugin Name: Anonymous OOP Action */
if ( ! class_exists( \'Anonymous_Object\' ) )
{
/**
* Add some actions with randomized global identifiers.
*/
class Anonymous_Object
{
public function __construct()
{
add_action( \'wp_footer\', array ( $this, \'print_message_1\' ), 5 );
add_action( \'wp_footer\', array ( $this, \'print_message_2\' ), 5 );
add_action( \'wp_footer\', array ( $this, \'print_message_3\' ), 12 );
}
public function print_message_1()
{
print \'<p>Kill me!</p>\';
}
public function print_message_2()
{
print \'<p>Me too!</p>\';
}
public function print_message_3()
{
print \'<p>Aaaand me!</p>\';
}
}
// Good luck finding me!
new Anonymous_Object;
}
现在我们看到:
WordPress需要name 用于过滤器。我们没有提供,所以WordPress打电话_wp_filter_build_unique_id()
并创建一个。此名称不可预测,因为它使用spl_object_hash()
.
如果我们运行var_export()
在…上$GLOBALS[\'wp_filter\'][ \'wp_footer\' ]
我们现在得到了这样的结果:
array (
5 =>
array (
\'000000002296220e0000000013735e2bprint_message_1\' =>
array (
\'function\' =>
array (
0 =>
Anonymous_Object::__set_state(array(
)),
1 => \'print_message_1\',
),
\'accepted_args\' => 1,
),
\'000000002296220e0000000013735e2bprint_message_2\' =>
array (
\'function\' =>
array (
0 =>
Anonymous_Object::__set_state(array(
)),
1 => \'print_message_2\',
),
\'accepted_args\' => 1,
),
),
12 =>
array (
\'000000002296220e0000000013735e2bprint_message_3\' =>
array (
\'function\' =>
array (
0 =>
Anonymous_Object::__set_state(array(
)),
1 => \'print_message_3\',
),
\'accepted_args\' => 1,
),
),
20 =>
array (
\'wp_print_footer_scripts\' =>
array (
\'function\' => \'wp_print_footer_scripts\',
\'accepted_args\' => 1,
),
),
1000 =>
array (
\'wp_admin_bar_render\' =>
array (
\'function\' => \'wp_admin_bar_render\',
\'accepted_args\' => 1,
),
),
)
为了找到并删除我们的邪恶行为,我们必须通过挂钩的相关过滤器(一个行为只是一个非常简单的过滤器),检查它是否是一个数组,以及对象是否是该类的实例。然后,我们取优先权并删除过滤器,
,而从未看到真正的标识符。好的,让我们把它放到一个函数中:
if ( ! function_exists( \'remove_anonymous_object_filter\' ) )
{
/**
* Remove an anonymous object filter.
*
* @param string $tag Hook name.
* @param string $class Class name
* @param string $method Method name
* @return void
*/
function remove_anonymous_object_filter( $tag, $class, $method )
{
$filters = $GLOBALS[\'wp_filter\'][ $tag ];
if ( empty ( $filters ) )
{
return;
}
foreach ( $filters as $priority => $filter )
{
foreach ( $filter as $identifier => $function )
{
if ( is_array( $function)
and is_a( $function[\'function\'][0], $class )
and $method === $function[\'function\'][1]
)
{
remove_filter(
$tag,
array ( $function[\'function\'][0], $method ),
$priority
);
}
}
}
}
}
我们什么时候调用这个函数?无法确定何时创建原始对象。也许以前有过\'plugins_loaded\'
? 也许以后?我们只使用与对象关联的同一个挂钩,并且很早就以优先级跳入0
. 只有这样才能真正确定。下面是如何删除该方法print_message_3()
:
add_action( \'wp_footer\', \'kill_anonymous_example\', 0 );
function kill_anonymous_example()
{
remove_anonymous_object_filter(
\'wp_footer\',
\'Anonymous_Object\',
\'print_message_3\'
);
}
结果:这将从您的问题中删除操作(未测试):
add_action( \'comments_array\', \'kill_FbComments\', 0 );
function kill_FbComments()
{
remove_anonymous_object_filter(
\'comments_array\',
\'SEOFacebookComments\',
\'FbComments\'
);
}
结论总是编写可预测的代码。为过滤器和操作设置可读名称。轻松移除任何挂钩在可预测的操作上创建对象,例如\'plugins_loaded\'
. 不仅仅是当你的插件被WordPress调用时