it-swarm.com.de

Wie oft wird dieser Code ausgeführt? (Oder wie reich ist Oma?)

Hypothetisches Beispiel, aber reale Anwendbarkeit (für jemanden, der lernt, wie ich).

Gegeben diesen Code:

<?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, jetzt rufe ich meine WP Seite auf und logge mich ein. Ich überquere ein paar Seiten in Admin. Die Aktion 'init' wird insgesamt 100 mal ausgelöst, bevor der Akku meines Laptops leer ist.

Erste Fragen: Wie viel Geld haben wir zu Oma geschickt? Ist es 1 $, 2 $, 100 $ oder 200 $ (oder etwas anderes?)

Wenn Sie auch Ihre Antwort erklären könnten, wäre das fantastisch.

Zweite Frage: Wenn wir sicherstellen wollen, dass wir nur Oma $ 1 schicken, wie geht das am besten? Globale Variable (Semaphor), die beim ersten Senden von $ 1 auf 'true' gesetzt wird? Oder gibt es einen anderen Test, um festzustellen, ob eine Aktion bereits stattgefunden hat und um zu verhindern, dass sie mehrmals ausgelöst wird?

Dritte Frage: Ist das etwas, worüber sich Plugin-Entwickler Sorgen machen? Mir ist klar, dass mein Beispiel albern ist, aber ich habe sowohl an Leistungsprobleme als auch an andere unerwartete Nebenwirkungen gedacht (z. B. wenn die Funktion in der Datenbank aktualisiert/eingefügt wird).

20
C C

Hier sind einige zufällige Gedanken dazu:

Frage 1

Wie viel Geld haben wir an Oma geschickt?

Für 100 Seiten haben wir ihr 100 x $ 1 = $ 100 geschickt.

Hier meinen wir eigentlich 100 x do_action( 'init' ) calls.

Es war egal, dass wir es zweimal hinzugefügt haben mit:

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

weil die Rückrufe und Prioritäten (Standard 10) identisch sind.

Wir können überprüfen, ob der add_action nur ein Wrapper für add_filter ist, der das globale $wp_filter-Array erstellt:

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

Wenn wir jedoch die Priorität geändert haben:

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

dann würden wir ihr 2 x 1 USD pro Seite oder 200 USD für 100 Seiten senden.

Dasselbe gilt, wenn die Rückrufe unterschiedlich waren:

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

Frage 2

Wenn wir sicherstellen wollen, dass wir nur Oma $ 1 schicken

Wenn wir es nur einmal pro Seite laden senden möchten, sollte dies folgendermaßen aussehen:

add_action( 'init','send_money_to_grandma' );

weil der Haken init nur einmal ausgelöst wird. Möglicherweise gibt es andere Hooks, die pro Seitenladevorgang mehrmals ausgelöst werden.

Lass uns anrufen:

add_action( 'someaction ','send_money_to_grandma' );

aber was passiert, wenn someaction 10 mal pro Seite geladen wird?

Wir könnten die Funktion send_money_to_grandma() mit anpassen

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

oder benutze eine statisch Variable als Zähler:

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

Wenn wir es nur einmal (jemals!) Ausführen möchten, registrieren wir möglicherweise eine Option in der wp_options -Tabelle über die Options-API :

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

Wenn wir ihr jeden Tag einmal Geld senden möchten, können wir die Transient API verwenden.

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

oder auch den wp-cron benutzen.

Beachten Sie, dass Sie möglicherweise Ajax-Aufrufe haben. auch.

Es gibt Möglichkeiten, nach solchen zu suchen, z. mit DOING_AJAX

Es kann auch Umleitungen geben, die den Fluss unterbrechen können.

Dann möchten wir uns vielleicht nur auf das Backend beschränken, is_admin() oder nicht: ! is_admin().

Frage 3

Ist das etwas, worüber sich Plugin-Entwickler Sorgen machen?

ja das ist wichtig.

Wenn wir unsere Oma sehr glücklich machen wollen, machen wir:

add_action( 'all','send_money_to_grandma' );

aber das wäre sehr schlecht für die leistung ... und unsere brieftasche ;-)

21
birgire

Dies ist eher ein Kommentar zur sehr guten Birgires Antwort als eine vollständige Antwort, aber da Sie Code schreiben müssen, passen Kommentare nicht.

Aus der Antwort geht hervor, dass der einzige Grund, warum im OP-Beispielcode eine Aktion einmal hinzugefügt wird, selbst wenn add_action() zweimal aufgerufen wird, die Tatsache ist, dass dieselbe Priorität verwendet wird. Das ist nicht wahr.

Im Code von add_filter ist ein wichtiger Teil _wp_filter_build_unique_id() Funktionsaufruf, der eine eindeutige ID per callback erstellt.

Wenn Sie eine einfache Variable verwenden, z. B. eine Zeichenfolge, die einen Funktionsnamen enthält, z. "send_money_to_grandma", dann ist die ID gleich der Zeichenkette selbst. Wenn also die Priorität gleich ist und auch die ID gleich ist, wird der Rückruf einmal hinzugefügt.

Es ist jedoch nicht immer so einfach. Rückrufe können alles sein, was in PHP callable ist:

  • funktionsnamen
  • statische Klassenmethoden
  • dynamische Klassenmethoden
  • aufrufbare Objekte
  • verschlüsse (anonyme Funktionen)

Die ersten beiden werden jeweils durch eine Zeichenfolge und ein Array von zwei Zeichenfolgen ('send_money_to_grandma' und array('MoneySender', 'send_to_grandma')) dargestellt, sodass die ID immer dieselbe ist und Sie sicher sein können, dass der Rückruf bei gleicher Priorität einmal hinzugefügt wird.

In allen anderen 3 Fällen hängt die ID von Objektinstanzen ab (eine anonyme Funktion ist ein Objekt in PHP), sodass der Rückruf nur dann hinzugefügt wird, wenn das Objekt das gleiche instance ist und es wichtig zu beachten ist dass dieselbe Instanz und dieselbe Klasse zwei verschiedene Dinge sind.

Nehmen Sie dieses Beispiel:

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

Wie viele Dollar senden wir pro Seite laden?

Die Antwort ist 2, weil die ID, die WordPress für $sender1 und $sender2 generiert, unterschiedlich ist.

Das gleiche passiert in diesem Fall:

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

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

Oben habe ich die Funktion sent_to_grandma innerhalb von Closures verwendet, und selbst wenn der Code identisch ist, sind die 2 Closures zwei verschiedene Instanzen von \Closure object, sodass WP zwei verschiedene IDs erstellt, wodurch die Aktion zweimal hinzugefügt wird , auch wenn die Priorität gleich ist.

8
gmazzap

Sie können nicht die gleiche Aktion zum gleichen Aktions-Hook mit der gleichen Priorität hinzufügen.

Dies wird getan, um zu verhindern, dass mehrere Plugins, die sich auf die Aktion eines Drittanbieters stützen, mehrmals ausgeführt werden (denken Sie an woocommerce und alle Plugins von Drittanbietern, wie Gateway-Zahlungsintegrationen usw.). Ohne Angabe der Priorität bleibt Oma also arm:

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

Wenn Sie diesen Aktionen jedoch Priorität hinzufügen, gilt Folgendes:

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

Oma stirbt jetzt mit 4 $ in der Tasche (1, 2, 3 und der Standard: 10).

4