Yanıtlar:
Bu çok iyi bir soru. Eklenti API'sinin karanlık kalbine ve en iyi programlama uygulamalarına kadar iner.
Aşağıdaki cevap için, kolay okunan kod ile sorunu göstermek için basit bir eklenti oluşturdum.
<?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;
}
Şimdi şunu görüyoruz:
WordPress , filtre için bir ada ihtiyaç duyar . Biz bir tane sağlamadık, bu yüzden WordPress çağırıyor _wp_filter_build_unique_id()
ve bir tane yaratıyor. Kullandığı için bu ad öngörülebilir değildir spl_object_hash()
.
Eğer var_export()
devam $GLOBALS['wp_filter'][ 'wp_footer' ]
edersek şuan böyle bir şey alırız:
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,
),
),
)
Kötü eylemimizi bulmak ve kaldırmak için, kancaya ilişkin filtrelerden geçmemiz gerekir (bir eylem sadece çok basit bir filtredir), bunun bir dizi olup olmadığını ve nesnenin sınıfın bir örneği olup olmadığını kontrol edin. Ardından önceliği alır ve filtreyi kaldırırız , gerçek tanıtıcıyı görmeden .
Tamam, hadi bunu bir işleve koyalım:
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
);
}
}
}
}
}
Bu işlevi ne zaman çağırırız? Özgün nesnenin ne zaman oluşturulduğundan emin olmanın hiçbir yolu yoktur. Belki bazen daha önce 'plugins_loaded'
? Belki sonra?
Nesnenin ilişkilendirildiği aynı kancayı kullanıyoruz ve önceliğe çok erken atlıyoruz 0
. Gerçekten emin olmanın tek yolu bu. Yöntemi nasıl kaldıracağımız şöyle 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'
);
}
Sonuç:
Ve bu eylemi sorunuzdan kaldırmalıdır (test edilmedi):
add_action( 'comments_array', 'kill_FbComments', 0 );
function kill_FbComments()
{
remove_anonymous_object_filter(
'comments_array',
'SEOFacebookComments',
'FbComments'
);
}
'plugins_loaded'
. Sadece eklentiniz WordPress tarafından çağrıldığında değil.plugins_loaded
çağrıldıklarında gerçekten eklendiklerinden emin olabilirler , bu tam olarak ne plugins_loaded
içindir. Tabii ki, sınıf örneğinin hâlâ erişilebilir olması gerekiyor, muhtemelen tekil desen.
remove_action()
Emin değilim ama bir singleton kullanmayı deneyebilirsiniz.
Nesne başvurusunu sınıfınızın statik özelliğinde saklamanız ve ardından statik değişkeni statik bir yöntemle döndürmeniz gerekir. Bunun gibi bir şey:
class MyClass{
private static $ref;
function MyClass(){
$ref = &$this;
}
public static function getReference(){
return self::$ref;
}
}
Nesneyi bildiğiniz sürece (ve PHP 5.2 veya daha üstünü kullanıyorsanız - mevcut kararlı PHP sürüm 5.5, 5.4 hala desteklenir, 5.3 kullanım ömrü sona erer), yalnızca yöntemle kaldırabilirsiniz remove_filter()
. Hatırlamanız gereken tek şey nesne, yöntem adı ve önceliğidir (kullanılıyorsa):
remove_filter('comment_array', [$this, 'FbComments']);
Ancak kodunuzda küçük bir hata yaparsınız. PHP ve (!) 'De gerekli olan ve uzun süre gecikmiş $this
olan ampersand ile ön ek yapmayın &
. Bu, kancalarınızla başa çıkmanızı sorunlu hale getirebilir, bu yüzden sadece yoldan bırakın
add_filter('comments_array', [$this, 'FbComments]));
Ve bu kadar.
$this
Dışarıdan erişiminiz yok (başka bir eklenti / tema).
&
hesabınızla ilgili&$this
bir PHP 4 şey,