Alternative to Globals

I have a set of variables that need to be accessible across my site. While I could declare them in my header.php file, I would prefer to define them in functions.php, or just not in a template file (view). Everything I read says DON’T USE GLOBAL’s…fine. But then what is the best way define these variables?

Here’s what I’m looking to define:

 global $favorites_array;
 global $user;
 global $user_id;
 global $user_name;
 global $uri;

 $user = wp_get_current_user();
 $user_name = $user->user_login;
 $user_id = $user->ID;
 $user_id = get_current_user_id();
 $uri = $_SERVER['REQUEST_URI'];

Related posts

Leave a Reply

3 comments

  1. The common advice you’ve found against using globals (or avoiding them whenever possible) is generally good advice, and you are correct to look first for alternatives rather than resorting to using them. The most common alternative is to pass the values into your functions as parameters.

    A lot of functionality of WordPress is already dependent on global variables, and looking into the source code it would seem that the function wp_get_current_user() is actually setting a global variable called $current_user.

    Multiple calls to wp_get_current_user() will immediately return if the global $current_user is already populated:

    if ( isset( $current_user ) && ( $current_user instanceof WP_User ) && ( $id == $current_user->ID ) )
        return $current_user;
    

    So looking over the list of variables you intended to set, I see no compelling need for any container variables on any of them. My advice would be to opt for explicit readability in your code wherever possible. Since WordPress supplies the function wp_get_current_user() whose purpose is to get that user, instead of creating a global $user and passing that around, make a call to the available function. It’s true that you cannot, for example, use the function call inside a string interpolation:

    // Can't do this:
    echo "The user is {wp_get_current_user()->user_login}";
    

    … and so in cases where you had otherwise intended to create a global variable for the user’s login, set a local on one in your function.

    function your_func() {
      $login = wp_get_current_user()->user_login;
      echo "The user is $login";
    }
    

    As for setting a variable like $user_id which serves as a container for the ID property of the user object, since ID is indeed a property of the user object, it makes good logical sense to maintain that relationship in your code. Though this may be faster to type:

    echo $user_id;
    

    This makes explicit the source of the variable:

    echo wp_get_current_user()->ID;
    // or even better, using the API function
    echo wp_get_current_user_id();
    

    Finally, with regard to the $_SERVER array, it is already a PHP superglobal array, available in all scopes without any extra effort needed. So instead of abstracting out one key from it in the form of:

    $uri = $_SERVER['REQUEST_URI'];
    

    I would opt to just make use of $_SERVER['REQUEST_URI'] directly in your own functions. If you find you need to use it several times in one function, for example, then feel free to create a local variable in the function:

    function uses_uri() {
      $uri = $_SERVER['REQUEST_URI'];
      echo "I like to say $uri over and over $uri $uri $uri";
    }
    

    But again, if you are using the superglobal value, your code will be more readable if it is used directly or the local variable is defined near where it is to be used (as opposed to a global variable defined in a separate include file whose value must be traced back to be understood).

    Because I am not terribly familiar with WordPress’ API, I cannot say for certain if it provides an API function to retrieve the request URI. I would not be surprised however, if such a function already exists and is conventionally used in WP code.

  2. You’re right, you shouldn’t use globals.
    One way around this is to put your theme code in a class and instantiate it.

    The example below uses a singleton style class definition with the variables your theme template files might need and I think it achieves what your trying to do.

    functions.php:

    class My_Theme {
        public $favorites_array;
        public $user;
        public $user_id;
        public $user_name;
        public $uri;
    
        protected function __construct(){
            // TODO: put all your add_filter and add_action calls here  
    
            $this->favorites_array = array();
            $this->user = wp_get_current_user();
            $this->user_name = $this->user->user_login;
            $this->user_id = get_current_user_id();
            $this->uri = $_SERVER['REQUEST_URI']; 
        }
    
        function get_instance() {
            static $instance;
            if( ! isset( $instance ) )
                $instance = new self();
    
            return $instance;
        }
    }
    
    My_Theme::get_instance();
    

    and then in header.php you could have:

    <?php
        $my_theme = My_Theme::get_instance();
    ?>
    <html>
        ...
        ...
        <title>Hello <?php echo( esc_html( $my_theme->user_name ) ); ?></title>
    

    I should also point out that by the looks of the variables you have, you probably only need $favorites_array because the others can all be retrieved using WordPress functions and are just redundant.

  3. Well, there is a lot of blog saying “Don’t use global” but in fact without explaining why. In all langages we have “global”. And it’s not seems to be a problem.
    The only “problem” we can find is that, in a large code, it can be hard to find problem wuth global as they are (on many cases) in a different file (a huge C dev can have more than 100 files).
    In PHP, the code is, often, short.

    What you must consider in fact, is using a naming convention to be able to detect quickly if a var is a global one or not.
    Eg naming them staring with “gl” or “glb”, as yo want.
    This avoid forgetting to put “global” at beginning of function.
    Use session, fucntion parameter global and so on. Each as positive and negative point. No need to avoid using one of them.

    Notice also if the value stay the same all over your code, maybe using a constant (DEFINE) can be another good option.

    Regards
    Peter