Using Multiple Queries of “home_url” vs. Calling a Variable Multiple Times

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>

Related posts

2 comments

  1. 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 Vagrantswordpress-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!

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

Comments are closed.