Câu trả lời:
Đó là một câu hỏi rất hay. Nó đi vào trái tim đen tối của API plugin và thực tiễn lập trình tốt nhất.
Đối với câu trả lời sau đây, tôi đã tạo một plugin đơn giản để minh họa vấn đề với mã dễ đọc.
<?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;
}
Bây giờ chúng ta thấy điều này:
WordPress cần một tên cho bộ lọc. Chúng tôi đã không cung cấp một cái, vì vậy WordPress gọi _wp_filter_build_unique_id()
và tạo một cái. Tên này không thể dự đoán được vì nó sử dụng spl_object_hash()
.
Nếu chúng ta chạy var_export()
trên $GLOBALS['wp_filter'][ 'wp_footer' ]
chúng ta sẽ nhận được một cái gì đó như thế này ngay bây giờ:
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,
),
),
)
Để tìm và loại bỏ hành động xấu xa của chúng ta, chúng ta phải đi qua các bộ lọc liên quan cho hook (một hành động chỉ là một bộ lọc rất đơn giản), kiểm tra xem đó có phải là một mảng không và liệu đối tượng có phải là một thể hiện của lớp không. Sau đó, chúng tôi ưu tiên và loại bỏ bộ lọc, mà không bao giờ nhìn thấy định danh thực sự .
Được rồi, hãy đặt nó vào một chức năng:
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
);
}
}
}
}
}
Khi nào chúng ta gọi chức năng này? Không có cách nào để biết chắc chắn khi đối tượng ban đầu được tạo. Có lẽ đôi khi trước đây 'plugins_loaded'
? Có lẽ sau này?
Chúng tôi chỉ sử dụng cùng một móc mà đối tượng được liên kết và nhảy vào rất sớm với mức độ ưu tiên 0
. Đó là cách duy nhất để thực sự chắc chắn. Đây là cách chúng tôi sẽ loại bỏ phương thức 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'
);
}
Kết quả:
Và điều đó sẽ loại bỏ hành động khỏi câu hỏi của bạn (không được kiểm tra):
add_action( 'comments_array', 'kill_FbComments', 0 );
function kill_FbComments()
{
remove_anonymous_object_filter(
'comments_array',
'SEOFacebookComments',
'FbComments'
);
}
'plugins_loaded'
. Không chỉ khi plugin của bạn được gọi bởi WordPress.plugins_loaded
được gọi, đó chính xác plugins_loaded
là những gì dành cho. Tất nhiên, thể hiện của lớp vẫn cần có thể truy cập được, có thể thông qua mẫu singleton.
remove_action()
Tôi không chắc nhưng bạn có thể thử sử dụng một singleton.
Bạn phải lưu trữ tham chiếu đối tượng trong một thuộc tính tĩnh của lớp và sau đó trả về biến tĩnh đó từ một phương thức tĩnh. Một cái gì đó như thế này:
class MyClass{
private static $ref;
function MyClass(){
$ref = &$this;
}
public static function getReference(){
return self::$ref;
}
}
Miễn là bạn biết đối tượng (và bạn sử dụng PHP 5.2 trở lên - phiên bản PHP ổn định hiện tại là 5.5, 5.4 vẫn được hỗ trợ, 5.3 là hết hạn sử dụng), bạn có thể xóa nó bằng remove_filter()
phương thức. Tất cả những gì bạn cần nhớ là đối tượng, tên phương thức và mức độ ưu tiên (nếu được sử dụng):
remove_filter('comment_array', [$this, 'FbComments']);
Tuy nhiên bạn làm một chút sai lầm trong mã của bạn. Không có tiền tố $this
với dấu và &
, điều cần thiết trong PHP 4 (!) Và nó đã quá hạn trong thời gian dài. Điều này có thể khiến việc xử lý các hook của bạn gặp vấn đề, vì vậy hãy bỏ qua nó:
add_filter('comments_array', [$this, 'FbComments]));
Và đó là nó.
$this
từ bên ngoài (một plugin / chủ đề khác).
&
khỏi cái của bạn&$this
, đó là thứ 4 của PHP