web-dev-qa-db-ja.com

"home_url"の複数のクエリの使用と変数の複数回の呼び出し

質問

1つのページテンプレートでhome_url()の複数のインスタンスを使用しているので、次の方法でページの読み込み時間が短縮されるのではないかと思いました。私の方法は、毎回home_url()を使用するのではなく、毎回home_url()の出力を変数に格納してから毎回その変数を呼び出すことです。

動機

変数をエコーするとページの読み込み時間が速くなると私が思ったのは、(私の理解が正しければ)その変数を呼び出すたびにデータベースを照会する必要がないからです。

方法A

<ul>
   <li><a href="<?php echo home_url(); ?>/category/blue">Blue Items</a></li>
   <li><a href="<?php echo home_url(); ?>/category/green">Green Items</a></li>
   <li><a href="<?php echo home_url(); ?>/category/red">Red Items</a></li>
   <li><a href="<?php echo home_url(); ?>/category/orange">Orange Items</a></li>
   <li><a href="<?php echo home_url(); ?>/category/purple">Purple Items</a></li>
   <li><a href="<?php echo home_url(); ?>/category/gray">Gray Items</a></li>
</ul>

方法B

<?php $my_home_url = home_url(); ?>       
<ul>
   <li><a href="<?php echo $my_home_url; ?>/category/blue">Blue Items</a></li>
   <li><a href="<?php echo $my_home_url; ?>/category/green">Green Items</a></li>
   <li><a href="<?php echo $my_home_url; ?>/category/red">Red Items</a></li>
   <li><a href="<?php echo $my_home_url; ?>/category/orange">Orange Items</a></li>
   <li><a href="<?php echo $my_home_url; ?>/category/purple">Purple Items</a></li>
   <li><a href="<?php echo $my_home_url; ?>/category/gray">Gray Items</a></li>
</ul>
1
Ademos

home_url()関数のソース を見ると、最終的にget_option()を呼び出す小さな一連の関数呼び出しに気付くでしょう。 このWPSE Answer で説明されているように、get_option()関数はキャッシュされます。つまり、オプションの値が既にメモリにある場合、get_option()はデータベースを再度クエリする代わりにその値を返します。その結果、1回のリクエストでhome_url()を1,000回呼び出した場合でも、データベースへのクエリは1回だけです。

メソッドB(ローカル変数の値を再利用する)には、メソッドA(必要に応じてhome_url()を呼び出します)は、関数呼び出しの束を呼び出しスタックに循環させません。とはいえ、最新のPHPのパフォーマンスを考えると、その差はごくわずかであり、数ミリ秒単位で測定することができます。

要するに、メソッドBは、無限の尺度による場合に限り、常に代替ソリューションよりも優れたパフォーマンスを発揮します。

補遺

コメントで要求されているように、サーバー環境の両方のメソッドの実行時間プロファイルを作成しました。そうすることで、回答の最後に添付されたプラグインを作成しました。これを使用して、独自の環境でメソッドをテストできます。

私の環境( Vaging Vagrant Vagrants 'wordpress-defaultサイト-PHP 5.4/MySQL 5.5/Nginx 1.4スタックを使用するUbuntu Server 12.04)、1000個のecho()で平均100個のプロファイルインスタンスの場合、私は次の結果を受け取りました:

方法A

GET文字列:?hup_method=a&hup_profiles=100&hup_instances=1000

100個のプロファイル全体で平均すると、メソッドAは0.023981981277466秒でhome_url()を1000回呼び出しました。

方法B

GET文字列:?hup_method=b&hup_profiles=100&hup_instances=1000

100個のプロファイル全体で平均すると、メソッドBは0.00071162700653076秒で$ homeUrlへの1000回の参照をecho()しました。

このプロファイルでは、メソッドBメソッドAよりも約34倍高速でした、メソッドBは0.7ミリ秒でecho() 'd 1000インスタンスを持ち、メソッドA管理されています。これは、home_url()の呼び出しを実行するのに約23マイクロ秒(0.000023秒)かかり、$homeUrl参照に従うのに0.7マイクロ秒(0.0000007秒)未満かかることを意味します(この時間の多くは、 home_url()Method B)で使用されています。

コードのパフォーマンスの複雑さに非常に興味がある場合は、「Big O Notation」について学習するか、個別の数学コンピューターサイエンスコースを見つけることをお勧めします。

<?php
/*
Plugin Name: Home URL Method Profiler
Plugin URI: https://wordpress.stackexchange.com/questions/136091
Description: Using Multiple Queries of “home_url” vs. Calling a Variable Multiple Times
Version: 0.1
Author: Adam Bosco
Author URI: https://wordpress.stackexchange.com/users/25324
License: GPL2
*/


class HomeUrlProfile {
    private static $hasPrinted = false;     // Only print out the results once
    private static $method = NULL;          // The method to profile
    private static $executionTimes = [];    // Profile results.
    private static $instanceCount = 1000;   // Number of instances of calls to home_url() or uses of $homeUrl to profile against
    private static $profileCount = 5;       // Number of times to run the same profile

    // Constructor; set up action hooks.
    public function HomeUrlProfile( $method ) {
        self::$method = strtolower( $method );

        if( isset( $_GET[ 'hup_instances' ] ) )
            self::$instanceCount = $_GET[ 'hup_instances' ];

        if( isset( $_GET[ 'hup_profiles' ] ) )
            self::$profileCount = $_GET[ 'hup_profiles' ];

        add_action( 'init', 'HomeUrlProfile::run' );
        add_action( 'loop_start', 'HomeUrlProfile::printResults' );
    }

    // Perform a profile
    public static function run() {
        // Perform the same profile of a method with the same number of echo()'d instances $profileCount times
        for( $i = 0; $i < self::$profileCount; $i++ ) {
            /* For a more realistic scenario, we'll actually echo the home URL for each
             * iteration. In order to avoid actually displaying all those URLs, we'll
             * capture the output in a buffer, then discard it after we get our execution
             * times. */
            ob_start();

            // Run the requested method and Push the results to the $executionTimes array;
            if( self::$method == 'a' )
                array_Push( self::$executionTimes, self::methodA() );
            else
                array_Push( self::$executionTimes, self::methodB() );

            // Clear the output buffer.
            ob_end_clean();

            // Remove home_url()'s cached values after each profile.
            wp_cache_delete( 'home', 'option' );
            wp_cache_delete( 'alloptions', 'options' );
        }
    }

    public static function printResults() {
        if( self::$hasPrinted )
            return;

        self::$hasPrinted = true;

        $averageTime = array_sum( self::$executionTimes ) / self::$profileCount;
?>
        <div>
            <h3>Home URL "Method <?php echo strtoupper( self::$method ); ?>" Profile Results</h3>
            <p>Averaged across <?php echo self::$profileCount; ?> profiles, Method <?php echo strtoupper( self::$method ); ?> echo()'d <?php echo self::$instanceCount; echo( self::$method == 'a' ? ' calls to home_url()' : ' references to $homeUrl' ); ?> in <?php echo $averageTime; ?> seconds.</p>
            <ol><?php
        foreach( self::$executionTimes as $executionTime ) {
            echo('
                <li>' . $executionTime . ' seconds</li>');
        }
            ?></ol>
        </div>
<?php
    }

    // "Method A" - using multiple calls to home_url().
    public static function methodA() {
        // Record the UNIX timestamp as a floating-point value before execution.
        $startTime = microtime( true );

        for( $i = 0; $i < self::$instanceCount; $i++ ) {
            echo( home_url() );
        }

        // Record the UNIX timestamp after execution
        $endTime = microtime( true );

        // Return the difference between the timestamps
        return $endTime - $startTime;
    }

    public static function methodB() {
        // Record the UNIX timestamp as a floating-point value before execution.
        $startTime = microtime( true );

        $homeUrl = home_url();

        for( $i = 0; $i < $instanceCount; $i++ ) {
            echo( $homeUrl );
        }

        // Record the UNIX timestamp after execution
        $endTime = microtime( true );

        // Return the difference between the timestamps
        return $endTime - $startTime;
    }
}

if( ! isset( $HomeUrlProfile ) && isset( $_GET[ 'hup_method' ] ) ) {
    $method = strtolower( $_GET[ 'hup_method' ] );

    switch( $method ) {
        case 'a':
        case 'b':
            break;
        default:
            die( 'Invalid Home URL profiling method specified (must be \'A\' or \'B\'): ' . $_GET[ 'hup_method' ] );
    }

    $HomeUrlProfile = new HomeUrlProfile( $method );
}

?>

GET変数hup_methodを設定すると、指定された値に応じてメソッドAまたはBのプロファイルが実行されます。 GET変数hup_instancesを使用して、プロファイル内のメソッドのエコーするホームURLの数を指定でき(デフォルトは1000)、変数hup_profilesを使用して回数を指定できますプロファイルを実行して平均を作成したい(デフォルトは5)。

このプロファイルをより正確にするにはさまざまな方法があります(たとえば、forループを実行するのにかかる時間を減算します)が、現在の形式では、関係する時間枠のかなり良い一般的なアイデアを提供します。

乾杯!

2
bosco

あなたはあなたの仮定に絶対に正しいです。 wp-includes/link-template.phpget_home_url()の実際の定義を見てください。

余談:home_url()は単にget_home_url()をエコーする便利なメソッドです。

以下は関数定義です。その出力を変数に割り当てることで、このコードを必要以上に5回呼び出すことによるパフォーマンスへの影響を回避できます。

function get_home_url( $blog_id = null, $path = '', $scheme = null ) {
    $orig_scheme = $scheme;

    if ( empty( $blog_id ) || !is_multisite() ) {
        $url = get_option( 'home' );
    } else {
        switch_to_blog( $blog_id );
        $url = get_option( 'home' );
        restore_current_blog();
    }

    if ( ! in_array( $scheme, array( 'http', 'https', 'relative' ) ) ) {
        if ( is_ssl() && ! is_admin() && 'wp-login.php' !== $GLOBALS['pagenow'] )
            $scheme = 'https';
        else
            $scheme = parse_url( $url, PHP_URL_SCHEME );
    }

    $url = set_url_scheme( $url, $scheme );

    if ( $path && is_string( $path ) )
        $url .= '/' . ltrim( $path, '/' );

    return apply_filters( 'home_url', $url, $path, $orig_scheme, $blog_id );
}
0
Cameron Hurd