1

Question

Since I am using multiple instances of home_url() in one page template, I was curious if the following method would speed up my page load time. My method is to store the output of home_url() within a variable and then call that variable each time, rather than using home_url() each time.

Motivation

The reason I thought echoing a variable would be speed up the page load time, is because (if my understanding is correct) echoing a variable wouldn't require querying the database, each time I called that variable.

Method 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>

Method 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>
2

If you look at the source for the home_url() function, you'll note a small series of function calls eventually invoking get_option(). As explained in this WPSE Answer, the get_option() function is cached, meaning that if an option's value is already in memory, get_option() returns that value instead of querying the database again. As a result, even if you call home_url() a thousand times during one request it will only query the database once.

That in mind, Method B (re-using the value from a local variable) still has a slight performance advantage over Method A (calling home_url() as needed) in that it doesn't cycle a bunch of function calls onto the call stack. That said, given modern PHP's performance, the difference is negligible and could be measured in a number of milliseconds, if not microseconds were one to profile the different approaches.

In short, Method B will always out-perform alternate solutions, if only by an infinitesimal measure.

Addendum

As requested in the comments, I have created execution time profiles of both methods for my server environment. In doing so, I created the plugin attached to the bottom of my answer, which you can use to test the methods in your own environment.

In my environment (Varying Vagrant Vagrants' wordpress-default site - Ubuntu Server 12.04 using a PHP 5.4/MySQL 5.5/Nginx 1.4 stack), averaging 100 profiles with 1000 echo()'d instances, I received the following results:

Method A

GET string: ?hup_method=a&hup_profiles=100&hup_instances=1000

Averaged across 100 profiles, Method A echo()'d 1000 calls to home_url() in 0.023981981277466 seconds.

Method B

GET string: ?hup_method=b&hup_profiles=100&hup_instances=1000

Averaged across 100 profiles, Method B echo()'d 1000 references to $homeUrl in 0.00071162700653076 seconds.

In this profile, Method B was about 34 times faster than Method A, Method B having echo()'d 1000 instances in 0.7 milliseconds, 23.2 milliseconds faster than Method A managed. This means that it took approximately 23 microseconds (0.000023 seconds) to execute a call to home_url(), and less than 0.7 microseconds (0.0000007 seconds) to follow a $homeUrl reference (much of this time can be attributed to the initial call to home_url() used in Method B).

If you're super interested in the complexities of code performance, I recommend spending some time learning about "Big O Notation," or finding a discrete mathematics computer science course.

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

?>

Setting the GET variable hup_method will run a profile for method A or B depending on the value specified. The GET variable hup_instances can be used to specify the number of home URLs to echo for the method in a profile (defaults to 1000), and the variable hup_profiles can be used to specify the number of times you would like to run the profile to create an average (defaults to 5).

There are various ways in which this profile could be made more accurate (subtracting the amount of time it takes to perform the for loop, for instance), but in it's present form it gives a pretty good general idea of the timeframes involved.

Cheers!

  • Thank you for your answer. It was helpful to know that the get_option function is cached in memory, since that was my technical motivation for storing the output of home_url in a variable. === However, though the performance difference would be negligible in a small group of home_url function calls, would that performance difference become more significant as I added more function calls? === For example, if my frontpage, header, sidebar and footer all contained groups of home_url function calls. – Ademos Feb 27 '14 at 3:46
  • Even were you to call home_url() a literal thousand times, I sincerely doubt the difference would peak at more than a quarter of a second (this is after all the tiniest portion of WordPress's core, and nothing remotely close to the most complex or resource intensive). If you're really interested in the absolute results, you can create a profile for your server environment by using calls to microtime( true ) to calculate run-times. Or give me a few hours and I'll profile a test case myself :) – bosco Feb 27 '14 at 3:54
  • Haha, thank you for your reassuring and technical answer. Given how often I use the home_url() function, I wanted to be sure that using it more often would not slow down the page loading time of my code. === If you are willing, I would certainly appreciate a test case to prove your hypothesis. – Ademos Feb 27 '14 at 4:16
  • Time profiles and a test-case plugin added :) . In my environment, the difference between echo()ing a call to home_url() and a $homeUrl reference was about 23 microseconds. – bosco Feb 27 '14 at 23:28
  • Wow, you certainly delivered a test case. Not only did you prove the performance difference between Method A and Method B was only about 23 microseconds. You also provided a plugin, in case I wanted to test the performance difference on my own server. === Thanks for the extra effort. I have marked your answer as accepted. – Ademos Feb 28 '14 at 0:09
0

You're absolutely right in your assumption. Look at the actual definition of get_home_url() in wp-includes/link-template.php.

aside: home_url() is just a convenience method that echos get_home_url().

Below is the function definition. By assigning it's output to a variable, you're avoiding the performance impact of calling this code 5 more times than necessary:

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 );
}
  • Thank you for including the lines of code for get_home_url, since I had a feeling that the home_url function was more complex than it appeared. === However, boscho mentioned that the performance difference between Method A and B is negligible. And if the performance is not significant, than perhaps storing the output in a variable is not worth the extra code. === Would you mind sharing your response to boscho's point? – Ademos Feb 27 '14 at 3:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.