Quante volte verrà eseguito questo codice? (o quanto è ricca la nonna?)


20

Esempio ipotetico ma applicabilità del mondo reale (per qualcuno che impara, come me).

Dato questo codice:

<?php

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

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

ok, ora apro il mio sito WP ed eseguo il login. Attraverso alcune pagine in Admin. L'azione "init" si attiva un totale di 100 volte prima che la batteria del mio laptop si esaurisca.

Prime domande: quanti soldi abbiamo inviato alla nonna? È $ 1, $ 2, $ 100 o $ 200 (o qualcos'altro?)

Se potessi anche spiegare la tua risposta sarebbe fantastico.

Seconda domanda: se vogliamo assicurarci di inviare solo nonna $ 1, qual è il modo migliore per farlo? Variabile globale (semaforo) che viene impostata su "true" la prima volta che inviamo $ 1? O c'è qualche altro test per vedere se un'azione è già avvenuta e impedire che si attivi più volte?

Terza domanda: è qualcosa di cui gli sviluppatori di plugin si preoccupano? Mi rendo conto che il mio esempio è sciocco, ma pensavo sia a problemi di prestazioni che ad altri effetti collaterali imprevisti (ad esempio se la funzione si aggiorna / inserisce nel database).


2
Devo ammetterlo, questa è una delle migliori domande da molto tempo ;-)
Pieter Goosen il

Risposte:


21

Ecco alcuni pensieri casuali su questo:

Domanda 1

Quanti soldi abbiamo inviato alla nonna?

Per 100 caricamenti di pagina, le abbiamo inviato 100 x $ 1 = $ 100.

Qui intendiamo effettivamente 100 x do_action( 'init' )chiamate.

Non importa che l'abbiamo aggiunto due volte con:

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

perché i callback e le priorità (default 10) sono identici .

Possiamo verificare come add_actionsia solo un wrapper per add_filterquello che costruisce l' $wp_filterarray globale :

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;
}

Se abbiamo comunque cambiato la priorità:

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

quindi le invieremo 2 x $ 1 per caricamento della pagina o $ 200 per 100 caricamenti della pagina.

Lo stesso se i callback erano diversi:

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

Domanda 2

Se vogliamo assicurarci di inviare solo nonna $ 1

Se vogliamo inviarlo solo una volta per caricamento della pagina , allora dovremmo farlo:

add_action( 'init','send_money_to_grandma' );

perché l' inithook viene sparato solo una volta. Potremmo avere altri hook che si attivano molte volte per caricamento della pagina.

Chiamiamo:

add_action( 'someaction ','send_money_to_grandma' );

ma cosa succede se viene someactiongenerato 10 volte per caricamento della pagina?

Potremmo regolare la send_money_to_grandma()funzione con

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

o usa una variabile statica come contatore:

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

Se vogliamo eseguirlo solo una volta (mai!), Potremmo registrare un'opzione nella wp_optionstabella tramite l' API delle opzioni :

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

Se vogliamo inviarle denaro una volta al giorno, allora possiamo usare l' API Transient

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 );
    }
}

o persino usare wp-cron.

Nota che potresti avere chiamate Ajax. anche.

Ci sono modi per verificare quelli, ad esempio con DOING_AJAX

Potrebbero esserci anche reindirizzamenti, che potrebbero interrompere il flusso.

Poi si potrebbe desiderare di limitare solo al backend is_admin()o meno: ! is_admin().

Domanda 3

È qualcosa di cui gli sviluppatori di plugin si preoccupano?

si questo è importante.

Se vogliamo rendere molto felice nostra nonna, faremmo:

add_action( 'all','send_money_to_grandma' );

ma questo sarebbe molto male per le prestazioni ... e il nostro portafoglio ;-)


wow - grazie per una risposta così approfondita; questo aiuta immensamente!
CC,

1
Prego - Mi è davvero piaciuto come hai formulato la tua domanda ;-) @CC
birgire

2
Alla fine della giornata, vogliamo mantenere felici i nostri portafogli e la nonna, quindi si tratta solo di trovare la perfetta armonia / equilibrio ;-)
Pieter Goosen

molto bella risposta +1, ma vale la pena dire che il modo in cui si aggiunge un'azione dipende anche dall'ID di callback e quando si tratta di oggetti le cose sono un po 'più complesse ... Difficile spiegare meglio il concetto qui, io' Scriverò una risposta ...
gmazzap

grazie @gmazzap - sì, sarebbe fantastico, dato che non ho coperto la terza chiave $ idx e _wp_filter_build_unique_id (), l'ho appena mostrata ;-)
birgire

8

Questo è più un commento all'ottima risposta di Birgire che una risposta completa, ma dovendo scrivere il codice, i commenti non vanno bene.

Dalla risposta può sembrare che l'unica ragione per cui un'azione viene aggiunta una volta nel codice di esempio OP, anche se add_action()viene chiamata due volte, è il fatto che viene utilizzata la stessa priorità. Non è vero.

Nel codice di add_filteruna parte importante è la _wp_filter_build_unique_id()funzione call, che crea un ID univoco per callback .

Se si utilizza una variabile semplice, come una stringa che contiene un nome di funzione, ad esempio "send_money_to_grandma", l'id sarà uguale alla stringa stessa, quindi se la priorità è la stessa, essendo lo stesso id, il callback viene aggiunto una volta.

Tuttavia, le cose non sono sempre così semplici. I callback possono essere tutto ciò che è callablein PHP:

  • nomi di funzioni
  • metodi di classe statica
  • metodi di classe dinamica
  • oggetti invocabili
  • chiusure (funzioni anonime)

I primi due sono rappresentati, rispettivamente, da una stringa e da una matrice di 2 stringhe ( 'send_money_to_grandma'e array('MoneySender', 'send_to_grandma')), quindi l'id è sempre lo stesso e si può essere certi che il callback venga aggiunto una volta se la priorità è la stessa.

In tutti gli altri 3 casi, l'id dipende dalle istanze di oggetto (una funzione anonima è un oggetto in PHP), quindi il callback viene aggiunto una volta solo se l'oggetto è la stessa istanza ed è importante notare che la stessa istanza e la stessa classe sono due cose diverse.

Prendi questo esempio:

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' ) );

Quanti dollari stiamo inviando per caricamento della pagina?

La risposta è 2, perché l'id WordPress genera per $sender1e $sender2sono diversi.

Lo stesso succede in questo caso:

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

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

Sopra ho usato la funzione sent_to_grandmaall'interno delle chiusure, e anche se il codice è identico, le 2 chiusure sono 2 diverse istanze di \Closureoggetto, quindi WP creerà 2 ID diversi, che causeranno l'aggiunta dell'azione due volte, anche se la priorità è la stessa.


4

Non è possibile aggiungere la stessa azione allo stesso hook di azioni , con la stessa priorità .

Questo viene fatto per evitare che più plug-in che dipendono dall'azione di un plug-in di terze parti avvengano più di una volta (si pensi al woocommerce e a tutti i suoi plug-in di terze parti, come le integrazioni di pagamento del gateway, ecc.). Quindi, senza specificare la priorità, la nonna rimane povera:

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');
}

Tuttavia, se aggiungi priorità a tali azioni:

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

La nonna ora muore con $ 4 in tasca (1, 2, 3 e il valore predefinito: 10).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.