it-swarm.com.de

Wie identifiziere ich Anfragen eindeutig?

Heute habe ich darüber nachgedacht, wie Abfragen zu unterscheiden sind, hauptsächlich um eine eindeutige Kennung zu erstellen. Dabei habe ich ein bisschen rumgespielt, siehe unten Code.

Die Hauptidee ist, dies in Abhängigkeit von der Eigenschaft $query oder $query_vars von WP_Query zu tun. Eigentlich gibt es bereits eine Eigenschaft query_vars_hash, diese wird jedoch relativ früh mit einer Teilmenge der Variablen erstellt und ist nicht hilfreich, um Abfragen zu unterscheiden, die bei derselben Anforderung auftreten.

Folgendes habe ich bisher:

add_action( 'pre_get_posts', 'unique_query' );
/**
 * unique_query
 *
 * Create unique identifier
 *
 */
function unique_query( $query ) {
    global $wp_query;
    $query_hashes = array();

    if ( is_admin() ) return;

    /**
     * Skip additional cases
     */
    /**
    if ( ! isset( $query->query['post_type'] )
        || empty( $query->query['post_type'] )
        || $query->query['post_type'] == 'nav_menu_item'
        || $query->is_main_query()
    ) {
        return;
    }
    /**/

    /**
     * Debug stuff
     */
    /**
    echo '<pre>';
        print_r( $query );
        print_r( $wp_query );
        print_r( $query->query );
        print_r( $wp_query->query );
        print_r( $query->query_vars );
        print_r( $wp_query->query_vars );
    echo '</pre>';
    /**/

    /**
     * Setup query hashes array
     */
    $query_hashes[ '$wp_query->query_vars_hash' ]  = $wp_query->query_vars_hash;
    $query_hashes[ 'uhash_$wp_query->query_vars' ] = md5( serialize( $wp_query->query_vars ) );
    $query_hashes[ '$query->query_vars_hash' ]     = $query->query_vars_hash;
    $query_hashes[ 'uhash_$query->query_vars' ]    = md5( serialize( $query->query_vars ) );
    $query_hashes[ 'uhash_$query->query' ]         = md5( serialize( $query->query ) );
    $query_hashes[ 'uhash_$wp_query->query' ]      = md5( serialize( $wp_query->query ) );

    /**
     * Print query hashes array
     */
    echo '<pre>';
        print_r( $query_hashes );
    echo '</pre>';

}


Was die folgende beispielhafte Ausgabe erzeugt:

/* Main query */
[$wp_query->query_vars_hash]  => ffb3c63f9b858ab4882d8e9ed20fce67
[uhash_$wp_query->query_vars] => ffb3c63f9b858ab4882d8e9ed20fce67
[$query->query_vars_hash]     => ffb3c63f9b858ab4882d8e9ed20fce67
[uhash_$query->query_vars]    => ffb3c63f9b858ab4882d8e9ed20fce67
[uhash_$query->query]         => 40cd750bba9870f18aada2478b24840a
[uhash_$wp_query->query]      => 40cd750bba9870f18aada2478b24840a

/* Query of wp_nav_menu */
[$wp_query->query_vars_hash]  => ffb3c63f9b858ab4882d8e9ed20fce67
[uhash_$wp_query->query_vars] => 59e1dad0ba690eed5e758fbf15cda702
[$query->query_vars_hash]     => c5a049c558df9cf4cfd14dad179a97e8
[uhash_$query->query_vars]    => c5a049c558df9cf4cfd14dad179a97e8
[uhash_$query->query]         => d4226d11be5a53e8b44d5b85db43e8b0
[uhash_$wp_query->query]      => 40cd750bba9870f18aada2478b24840a

/* Front/home query */
[$wp_query->query_vars_hash]  => ffb3c63f9b858ab4882d8e9ed20fce67
[uhash_$wp_query->query_vars] => 59e1dad0ba690eed5e758fbf15cda702
[$query->query_vars_hash]     => 712b303f79eef3c8b5928d4ed8acfe2f
[uhash_$query->query_vars]    => 712b303f79eef3c8b5928d4ed8acfe2f
[uhash_$query->query]         => b7ac5bdfe084209f0142d7ab3aa0683e
[uhash_$wp_query->query]      => 40cd750bba9870f18aada2478b24840a


Wie Sie sehen, sind die einzigen Kandidaten für eine eindeutige Bestimmung $query->query_vars_hash/uhash_$query->query_vars oder uhash_$query->query. In diesem Beispiel sind natürlich das erste und das zweite identisch, aber in Zukunft müssen möglicherweise Dinge erledigt werden, die von der vorhandenen Eigenschaft query_vars_hash nicht abgedeckt werden. Außerdem musst du es selbst machen, um sicherzugehen.

Die Frage wäre also erstens: Ist dies ein vernünftiger Ansatz, um Abfragen eindeutig zu identifizieren? Oder fehlt mir etwas, besonders, gibt es vielleicht ein besseres, also zweitens, wenn jemand eine Eingabe hat, bin ich interessiert.


Bearbeiten:

@ G.M. In Bezug auf alles, was mit dem angesprochenen Problem in Zusammenhang gebracht wurde, stimmt es ziemlich genau. Eigentlich wollte ich diese Informationen hinzufügen, hatte zum Zeitpunkt der Veröffentlichung einfach nicht genug Zeit, jetzt wäre es einfach überflüssig, aber ich wollte die Tatsache bestätigen.

5
Nicolai

tl; dr : erschwingliche eindeutige Bezeichner für Abfragen zu erstellen ist möglich, aber ziemlich nutzlos.


Wenn Sie nach eindeutigen Bezeichnern für die Abfrage objects suchen, können Sie spl_object_hash verwenden, aber IMHO ist ziemlich nutzlos: Es ist nicht vorhersehbar, und Sie erhalten auch eine andere ID, selbst wenn die Abfrage unterschiedlich ist sind identisch, aber auf 2 verschiedene Abfrageobjekte gesetzt. Als einziger Grund für die Verwendung kann eine Statistik wie die folgende angegeben werden: "Während dieser Anforderung wurden XX verschiedene WP_Query-Objekte instanziiert."

Wenn Sie auf die Abfrage Variablen aufmerksam gemacht haben, liegt dies wahrscheinlich daran, dass Sie nach einer ID suchen, um die Abfrage Ergebnisse zu identifizieren. Wenn Sie also dieselbe ID von 2 verschiedenen Abfrageobjekten abrufen können, sollten die Ergebnisse für beide Abfragen gleich sein.

In diesem Fall habe ich eine böse Überraschung für Sie: Das wird niemals passieren, denn unabhängig von der verwendeten Technik berücksichtigen Sie 'posts_*'-Filter ('posts_where', 'posts_where') nicht, wenn Sie Ihre Abfrage-ID auf Basis von Abfragevariablen erstellen. posts_join 'und so weiter, das sind 19 IIRC).

Konzeptioneller Beweiß:

$query1 = new WP_Query( 'post_type=post' );

add_filter( 'posts_where', function() { return ' AND 1 = 0'; } );

$query2 = new WP_Query( 'post_type=post' );

$query1 und $query2 sind identisch, daher gibt ein virtueller Rückruf, der eine eindeutige ID basierend auf Abfragevariablen zurückgibt, für die beiden Abfragen die gleiche ID zurück, aber die erste Abfrage gibt alle veröffentlichten Beiträge zurück, die zweite Abfrage gibt nichts zurück.

Dies ist der Grund, warum Abfragevariablen kein guter Ausgangspunkt für die Erstellung einer eindeutigen Abfrage-ID sind.

Wenn es auf die Abfrageergebnisse ankommt, sollten Sie sich auf die Abfrage-SQL-Anforderung konzentrieren: Wenn die Anforderung identisch ist, sind die Ergebnisse identisch. Außerdem ist die Anforderung eine Zeichenfolge, die leicht zu hashen ist.

Ein guter Kandidaten-Hook für den Bereich sollte einer sein, wenn die Anforderung vollständig erstellt, aber noch nicht ausgeführt wurde. 'split_the_query' filter hook sollte in Ordnung sein.

// prepare our ids storage
add_action( 'init', function() {
   global $query_ids;
   $query_ids = array();
});

// use the filter to build and store the id
add_filter( 'split_the_query', function( $split_the_query, $query ) {
  $hash = md5( $query->request );
  $hash .= $split_the_query ? '_split' : '';
  global $query_ids;
  if ( ! in_array( $hash, $query_ids, TRUE ) ) {
    $query_ids[] = $hash; // store hash if not already stored
  }
  return $split_the_query; // return $split_the_query as is
}, PHP_INT_MAX, 2 );

Jetzt haben wir eine Möglichkeit, eindeutige Abfrage-IDs zu erstellen: Wenn wir dieselbe ID aus zwei Abfragen erhalten können, sind die Ergebnisse der beiden Abfragen identisch.

Aber was können wir damit machen? Vielleicht eine Statistik wie:

add_action('shutdown', function() {
   global $query_ids;
   echo count( $query_ids ) . " different WP_Query requests were performed.";
});

Ich kann nicht herausfinden, wie nützlich eine solche Statistik ist, aber vielleicht kann es jemand.

Ich weiß, dass Sie darüber nachdenken, den Abfragebezeichner zum Cache der Abfrage zu verwenden und keine Datenbankanforderung auszulösen, wenn die ID dieselbe ist, und das ist eine gute Idee, aber ... Sie können nicht .

Das Problem ist, dass wenn WordPress die Anfrage erstellt hat, sie sofort ausgeführt wird und Sie keine Chance haben, sie kurzzuschließen!

Oder besser, wenn WordPress $wpdb->get_results zum Ausführen der Abfrage verwendet und $wpdb eine globale Variable ist, besteht die Möglichkeit, dieses Objekt durch eine geänderte, cachefähige wpdb-Klasse zu ersetzen. Dies ist eine gute Idee, macht aber in diesem Fall keinen Sinn eindeutige ID für die Abfragen, sobald der gesamte Cache auf $wpdb basierend auf den dort ausgeführten SQL-Anforderungen ausgeführt wurde.

Grundsätzlich besteht das Problem darin, dass WordPress unter 2 großen Problemen in Bezug auf die WP_Query-Logik leidet (unter anderem über den WP_Query-chaotischen Code):

  1. der Prozess von building der Abfrage und der Prozess von running der Abfrage sind nicht trennbar
  2. die Abfrage kann nicht kurzgeschlossen werden: Wenn die Methode WP_Query::get_posts() einmal aufgerufen wurde, kann die Ausführung der SQL-Abfrage nicht mehr verhindert werden

Bis diese beiden Probleme bestehen bleiben, kann IMHO eine eindeutige ID für Abfragen erstellen, die nur für exzentrische Statistiken verwendet werden kann ...

4
gmazzap