Bu kod kaç kez çalışır? (veya büyükanne ne kadar zengin?)


20

Varsayımsal örnek ama gerçek dünya uygulanabilirliği (benim gibi öğrenen biri için).

Bu kod verildiğinde:

<?php

function send_money_to_grandma() {
     internetofThings("send grandma","$1");
}

add_action('init','send_money_to_grandma');
add_action('init','send_money_to_grandma');

tamam, şimdi WP sitemi açıp giriş yapıyorum. Yönetici'de birkaç sayfa geçiyorum. Dizüstü bilgisayarımın pili bitmeden önce 'init' eylemi toplam 100 kez patlar .

İlk sorular: Büyükanneme ne kadar para gönderdik? 1 $, 2 $, 100 $ veya 200 $ (veya başka bir şey mi?)

Cevabınızı da açıklayabilirseniz, bu harika olurdu.

İkinci sorular: Büyükannemize sadece 1 dolar gönderdiğimizden emin olmak istiyorsak, bunu yapmanın en iyi yolu nedir? İlk kez 1 $ gönderdiğimizde 'true' olarak ayarlanan global değişken (semafor)? Veya bir eylemin gerçekleşip gerçekleşmediğini görmek ve bunun birden çok kez tetiklenmesini önlemek için başka bir test var mı?

Üçüncü soru: Bu, eklenti geliştiricilerinin endişe ettiği bir şey mi? Örneğimin saçma olduğunu fark ettim ama hem performans sorunlarını hem de diğer beklenmedik yan etkileri düşünüyordum (örneğin, işlev güncelleştirilir / veritabanına eklenirse).


2
İtiraf etmeliyim ki, bu uzun zamandır en iyi sorulardan biri ;-)
Pieter Goosen

Yanıtlar:


21

İşte bu konuda bazı rastgele düşünceler:

Soru 1

Büyükanneme ne kadar para gönderdik?

100 sayfa yüklemesi için ona 100 x $ 1 = 100 $ gönderdik.

Burada aslında 100 x do_action( 'init' )çağrı demek istiyoruz .

İki kez eklediğimiz önemli değildi:

add_action( 'init','send_money_to_grandma' );
add_action( 'init','send_money_to_grandma' );

çünkü geri aramalar ve öncelikler (varsayılan 10) aynıdır .

Küresel diziyi add_actionoluşturan add_filterbunun nasıl bir sarıcı olduğunu kontrol edebiliriz $wp_filter:

function add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
        global $wp_filter, $merged_filters;

        $idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority);
        $wp_filter[$tag][$priority][$idx] = array(
            'function'      => $function_to_add, 
            'accepted_args' => $accepted_args
        );
        unset( $merged_filters[ $tag ] );
        return true;
}

Ancak önceliği değiştirirsek:

add_action( 'init','send_money_to_grandma', 9 );
add_action( 'init','send_money_to_grandma', 10 );

sayfa başına 2 x 1 TL veya 100 sayfa yüklemesi için 200 TL göndeririz.

Farklı yerlerde geri aramalar varsa:

add_action( 'init','send_money_to_grandma_1_dollar' );
add_action( 'init','send_money_to_grandma_also_1_dollar' );

Soru 2

Sadece büyükannem $ 1 gönderdiğimizden emin olmak istiyorsak

Sayfa yükü başına yalnızca bir kez göndermek istiyorsak, bunu yapmalıyız:

add_action( 'init','send_money_to_grandma' );

çünkü initkanca sadece bir kez ateşlenir. Sayfa yükleme başına birçok kez tetiklenen başka kancalarımız olabilir.

Hadi arayalım:

add_action( 'someaction ','send_money_to_grandma' );

ancak someactionsayfa yükleme başına 10 kez tetiklenirse ne olur ?

send_money_to_grandma()İşlevi ayarlayabiliriz

function send_money_to_grandma() 
{
    if( ! did_action( 'someaction' ) )
        internetofThings("send grandma","$1");
}

veya sayaç olarak statik bir değişken kullanın :

function send_money_to_grandma() 
{
    static $counter = 0;
    if( 0 === $counter++ )
        internetofThings("send grandma","$1");
}

Yalnızca bir kez (hiç!) Çalıştırmak istiyorsak wp_options, Seçenekler API'sı aracılığıyla tabloya bir seçenek kaydedebiliriz :

function send_money_to_grandma() 
{
    if( 'no' === get_option( 'sent_grandma_money', 'no' ) )
    {
        update_option( 'sent_grandma_money', 'yes' );
        internetofThings( "send grandma","$1" );
    }
}

Parasını her gün bir kez göndermek istiyorsak, Geçici API'yı kullanabiliriz

function send_money_to_grandma() 
{
    if ( false === get_transient( 'sent_grandma_money' ) ) )
    {
        internetofThings( "send grandma","$1" );
        set_transient( 'sent_grandma_money', 'yes', DAY_IN_SECONDS );
    }
}

hatta wp-cron kullanın.

Ajax çağrılarınız olabileceğini unutmayın. de.

Bunları kontrol etmenin yolları vardır, örneğin DOING_AJAX

Ayrıca akışı kesintiye uğratabilecek yönlendirmeler de olabilir.

Sonra sadece, arka uçta kısıtlamak isteyebilirsiniz is_admin()ya da değil: ! is_admin().

Soru 3

Bu eklenti geliştiricilerinin endişe ettiği bir şey mi?

evet bu önemlidir.

Büyükannemizi çok mutlu etmek istiyorsak:

add_action( 'all','send_money_to_grandma' );

ama bu performans için çok kötü olurdu ... ve cüzdanımız ;-)


vay - böyle kapsamlı bir yanıt için teşekkür ederim; bu çok yardımcı olur!
CC

1
Rica ederim
Sorunuzu

2
Günün sonunda, cüzdanlarımızı ve büyükannemizi mutlu etmek istiyoruz, bu yüzden hepsi mükemmel bir uyum / denge bulmakla ilgili ;-)
Pieter Goosen

çok güzel bir cevap +1, ancak bir eylemin nasıl eklenebileceği de geri arama kimliğine bağlıdır ve nesnelerle uğraşırken işler biraz daha karmaşıktır ... Buradaki kavramı daha iyi açıklamak zor. ll bir cevap yaz ...
gmazzap

thanks @gmazzap - evet bu harika olurdu, çünkü üçüncü anahtarı $ idx ve _wp_filter_build_unique_id () kapsamadım, sadece görüntüledi ;-)
birgire

8

Bu, çok iyi Birgire'nin cevabına tam bir cevaptan daha çok bir yorum , ancak kod yazmak zorunda kaldığınızda yorumlar uymuyor.

Yanıttan, OP örnek koduna bir add_action()kez iki kez çağrılsa bile, eylemin bir kez eklenmesinin tek nedeni , aynı önceliğin kullanılması gerçeği gibi görünebilir . Bu doğru değil.

add_filterÖnemli bir parçanın kodunda, geri arama_wp_filter_build_unique_id() başına benzersiz bir kimlik oluşturan işlev çağrısı bulunur .

Örneğin "send_money_to_grandma", bir işlev adını tutan bir dize gibi basit bir değişken kullanırsanız , id dizenin kendisine eşit olacaktır, bu nedenle öncelik aynıysa, id aynı olduğunda, geri çağrı bir kez eklenir.

Ancak, işler her zaman böyle basit değildir. Geri aramalar callablePHP'de olan herhangi bir şey olabilir :

  • işlev adları
  • statik sınıf yöntemleri
  • dinamik sınıf yöntemleri
  • çağrılabilir nesneler
  • kapanışlar (anonim işlevler)

İlk ikisi, sırasıyla, bir dize ve 2 dize ( 'send_money_to_grandma've array('MoneySender', 'send_to_grandma')) dizisi ile temsil edilir, böylece kimlik her zaman aynıdır ve öncelik aynıysa geri aramanın bir kez eklendiğinden emin olabilirsiniz.

Diğer tüm 3 durumda, id nesne örneklerine bağlıdır (anonim işlev PHP'deki bir nesnedir), bu nedenle geri arama yalnızca nesne aynı örnekse bir kez eklenir ve aynı örneğin ve aynı sınıfın not edilmesi önemlidir iki farklı şeydir.

Bu örneği ele alalım:

class MoneySender {

   public function sent_to_grandma( $amount = 1 ) {
     // things happen here
   }

}

$sender1 = new MoneySender();
$sender2 = new MoneySender();

add_action( 'init', array( $sender1, 'sent_to_grandma' ) );
add_action( 'init', array( $sender1, 'sent_to_grandma' ) );
add_action( 'init', array( $sender2, 'sent_to_grandma' ) );

Sayfa başına yükleme başına kaç dolar gönderiyoruz?

Cevap 2'dir, çünkü WordPress kimliği üretir $sender1ve $sender2farklıdır.

Bu durumda aynı şey olur:

add_action( 'init', function() {
   sent_to_grandma();
} );

add_action( 'init', function() {
   sent_to_grandma();
} );

Yukarıda işlevi sent_to_grandmakapanışların içinde kullandım ve kod aynı olsa bile, 2 kapanış \Closurenesnenin 2 farklı örneğidir , bu nedenle WP, öncelik aynı olsa bile, eylemin iki kez eklenmesine neden olacak 2 farklı kimlik oluşturur.


4

Sen ekleyemezsiniz aynı eylemi için aynı eylem kanca ile, aynı önceliğe .

Bu, bir üçüncü taraf eklentinin eylemine dayanan birden fazla eklentinin birden fazla olmasını önlemek için yapılır (woocommerce'i ve ağ geçidi ödeme entegrasyonları gibi tüm üçüncü taraf eklentilerini düşünün). Dolayısıyla, büyükanne önceliği belirtmeden zayıf kalır:

add_action('init','print_a_buck');
add_action('init','print_a_buck');

function print_a_buck() {
    echo '$1</br>';
}
add_action('wp', 'die_hard');
function die_hard() {
    die('hard');
}

Ancak, bu işlemlere öncelik eklerseniz:

add_action('init','print_a_buck', 1);
add_action('init','print_a_buck', 2);
add_action('init','print_a_buck', 3);

Büyükanne şimdi cebinde 4 $ ile ölüyor (1, 2, 3 ve varsayılan: 10).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.