web-dev-qa-db-ja.com

クエリを一意に識別する方法

今日は、主に一意の識別子を作成するために、クエリをどのように区別するかを考えていました。私が少し遊んだ過程で、以下のコードを見てください。

主な考え方は、$query$query_varsまたはWP_Queryプロパティに応じてそれを行うことです。実際には既にquery_vars_hashというプロパティがありますが、varのサブセットでかなり早く作成されているため、同じリクエストで発生したクエリを区別するのに役立ちません。

以下は私がこれまでに持っているものです:

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

}


これにより、次のような出力例が生成されます。

/* 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


お分かりのように、明確な決定のための唯一の候補は$query->query_vars_hash/uhash_$query->query_varsまたはuhash_$query->queryです。もちろんこの例では1番目と2番目のものは同じですが、将来的には既存のquery_vars_hashプロパティでカバーされていないことをする必要があるかもしれません。確かに自分でやらなければなりません。

これはクエリを一意に識別するための合理的なアプローチですか?または、特に何かが足りない場合は特に、より良いものがある可能性があります。 、 興味ある。


編集:

@ G.提起された問題で暗示されたすべてのことについてほとんど正しいです。私は実際にこの情報を追加することを心に留めていました、投稿する時点でちょうど十分な時間がありませんでした、今それはただ冗長になるでしょう、しかし私は事実を確認したかったです。

5
Nicolai

tl; dr:手ごろな価格でクエリ用の一意の識別子を作成することは可能ですが、まったく役に立ちません。


Query objects の一意の識別子を探しているなら、 spl_object_hash を使うことができますが、IMHOはまったく役に立ちません。それは予測不可能であり、query varsであっても異なるIDを得ます。同一ですが、2つの異なるクエリオブジェクトに設定されます。 "このリクエストの間にXX個のWP_Query個のオブジェクトがインスタンス化されました。"

Query variables に注意を向けたのは、おそらくquery results を識別するためのIDを探しているからです。つまり、2つの異なるqueryオブジェクトから同じidを取得できる場合両方のクエリで同じにします。

そのような場合、私はあなたにとって悪い驚きです:あなたが使用するテクニックに関係なく、あなたがクエリ変数に基づいてあなたのクエリIDを構築するなら、あなたは'posts_*' filters( 'posts_where'、 'を考慮しません) posts_join 'など、それらは19 IIRCです。

コンセプトの証明:

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

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

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

$query1$query2は同一なので、クエリvarsに基づいて一意のIDを返す仮想コールバックは2つのクエリに対して同一のIDを返しますが、最初のクエリはすべての公開された投稿を返し、2番目のクエリは何も返しません。

これが、クエリ変数が一意のクエリIDを構築するための良い出発点ではない理由です。

クエリの結果が重要な場合は、クエリのSQLリクエストに集中する必要があります。リクエストが同じ場合、結果は同じになります。さらに、リクエストは文字列なので、簡単にハッシュできます。

スコープの適切な候補フックは、リクエストが完全に構築されているがまだ実行されていない場合に1つにする必要があります。 'split_the_query' filterフックは問題ないはずです。

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

これで、一意のクエリ識別子を作成する方法があります。2つのクエリから同じ識別子を取得できる場合、2つのクエリの結果は同じになります。

しかし、それを使って何ができるでしょうか。おそらく以下のような統計です。

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

そのような統計の有用性が何であるか私にはわかりませんが、誰かができるかもしれません。

cache クエリにクエリ識別子を使用することを考えているのですが、idが同じ場合はデータベースリクエストをトリガーしません。 。

問題は、WordPressがリクエストを作成した後すぐにそれを実行し、それをショートする機会がないということです。

あるいは、WordPressが$wpdb->get_resultsを使用してクエリを実行し、$wpdbがグローバル変数になったら、そのオブジェクトをキャッシュ可能な変更されたwpdbクラスに置き換えることをお勧めしますが、その場合は意味がありません。 sqlリクエストに基づいてすべてのキャッシュが$wpdb上で発生した後のクエリの一意のIDがそこで実行されました。

実質的には、問題はWordPressがWP_Queryロジックに関して2つの大きな問題を抱えていることです(とりわけ、WP_Query厄介なコードについて)。

  1. building の処理と running の処理は分離できません
  2. クエリを短絡する方法はありません。一度WP_Query::get_posts()メソッドが呼び出されると、sqlクエリが実行されるのを防ぐ方法はありません。

これらの2つの問題がそこにとどまるまで、私見はクエリのためにユニークなidを作成することは偏心した統計のためにだけ使われることができるものです...

4
gmazzap