Global variables in WordPress

WordPress logo In my critique of the code in WordPress I talked about the frequent use of global variables, something this I think it a bad practice. In response Owen Winkler writes that:

Global variables are used in WordPress in many places to make things simpler for a novice end-user to design. […]

The point is that novice plugin and template designers shouldn’t have to worry about object-oriented syntax, and therefore lots of object members are put into the global scope.

It might be easy, but I still find this a poor way to pass information around in an application. The global variables obscure the relationship between functions. Take my example from the original rant, the mysql2date() function — it’s the second function (or third, depending on whether or not you expect Gettext to be active) in wp-includes/functions.php.

The first line in the body declares four global variables named $month, $weekday, $month_abbrev, and $weekday_abbrev. So this function is obviously somehow dependent on those variables being initialized. So the first question is: can I always call mysql2date()? Do I first have to call some initialization function, or is this guaranteed to be done for me when I want to use mysql2date() in some plugin or template?

It’s not such a big mystery to figure out where the variables come from: a quick grep reveals that they are defined in locale.php. But who takes care of including locale.php? Another grep, and one sees that this is done by wp-settings.php — I guess that file is always loaded, and thus one can be sure that $month and the other globals are indeed initialized before a call to mysql2date().

No wait! On close inspection of wp-settings.php one sees that locale.php is loaded after the active plugins are loaded, and after a call to do_action('plugins_loaded'). So does this mean that a

plugin that attaches itself to the plugins_loaded action cannot call mysql2date()? I believe it does!

In my installation I found no other references to the plugins_loaded action, and so this could explain why this bug wasn’t found earlier. But in any case — if the developers had taken the time to properly document this dependency between locale.php and functions.php, then the problem should never have occurred in the first place.

This potential bug wasn’t the reason for my initial worries about the use of global variables: I had been trying to get the Smart link plugin working. It uses a global $comments variable to know which comments to process, but the comments.php template doesn’t define it to be global — in fact the $comments variable is a local variable in the comments_template() function in comment-functions.php. This function includes comments.php, and thus $comments has the local scope in that file. (These scope rule games in PHP are just so annoying!)

I now see that the problem that triggered my anger against the global variables was in fact a use of a non-global variable, expecting it to be global. A bit ironic that I were to find a problem with a totally different function, mysql2date(), while initially being started by a mistake in a plugin…

4 Comments »

Comment by Owen
2005-05-24 12:15:05

Only really two points of concern here:

In what way would you suggest that not using global variables would have fixed the problem with mysql2date()? Since you seem to have tracked down the issue to thoroughly to know the answer to this question, why haven’t you written a patch for the specified bug?

Your analysis of the failure of the plugins_loaded bug doesn’t mention that the plugin hook init is a better choice for the operation you’re trying to accomplish. plugins_loaded would let a plugin affect the locale settings, which would be impossible if the locale settings were loaded first. init occurs after the locale settings are set, and so manke much more sense for use in this case. Note that the call to sink init hooks is 23 lines down the file from the plugins_loaded hook.

So who can be blamed if you don’t fully understand PHP’s scope rules or WordPress’ call order?

Comment by Martin Geisler
2005-05-24 20:57:54

The idea of my example was to point out that the use of global variables is dangerous because it leads to different parts of the code being connected in non-obvious ways.

So whenever they are used, such connections must be prominently documented, and here — like in almost all other places in the WordPress code where I’ve looked — there were no comments in mysql2date() to indicate that locale.php must be loaded first.

I haven’t written a patch because I only just traced through the code this morning before heading to Uni, and because I’m not sure that just moving things around a little in wp-settings.php would be enough — I might mess up some other code elements which share a weak link.

The choice of mysql2date() was random, and I didn’t expect to find such a problem at first; I expected to use the function as an example of the kind of integrity checks that must be maintained when using global variables: have they been properly initialized. At first I thought that everything was fine, and that the variables were guaranteed to be loaded — but then I looked at the code again and realized that it wasn’t as bullit-proof as it appears.

As for your last point, then I think it’s pretty easy to say who is to be blamed if I don’t fully understand the call order in WordPress: the developers who neglected to comment their code. I know how to both read code and how to debug code — but I much prefer to do the first. Having comments in the code is a great way to make it readable.

About the scope rules of PHP, then I believe I can say that I indeed understand them. That’s not so hard afterall — they are documented in the manual.

 
 
Comment by Philip Subscribed to comments via email
2006-02-01 20:02:57

Martin,

I read this entry a couple of months ago (searching for evidence why all-globals is bad), found it interesting, bookmarked it, and promptly forgot about it.

Recently I started hacking around in WP a bit, and my reaction was very similar to yours. Trying to “make things easier” for newbies by using all globals is foolhardy. Sure, you’re saving them learning a bit about OO — but you’re also training them that this is a good thing. I recognize that blogs are meant to be more accessible/hackable to the non-technical than other apps. But I still believe that “dumbing down” by using poor coding practices is a bad trade-off with spillover effects outside the particular project at hand.

WP 2 looks marginally better in this regard, but only marginally. I suppose I should search your blog and see if you’ve commented on it.

Comment by Martin Geisler
2006-02-01 20:25:04

Thanks for your comments, I’m glad to hear that I’m not all offtrack in my critique :-)

And about WordPress 2: no need to search for my comments on it — I haven’t bothered to upgrade to WP 2 yet. And from what I’ve read about it around the net I’ll wait a bit more… (also because I have little time right now).

 
 
Name (required)
E-mail (required - never shown publicly)
URI (optional)
Your Comment (smaller size | larger size)

Formatted using Markdown: use blank lines to separate paragraphs, * for emphasis, and backticks (`) around code.

(Googlebot visited this page Saturday, May 20, 2006)