July 22, 2006

Why Global Variables in PHP is Bad Programming Practice

Posted at July 22, 2006 08:32 PM in MediaWiki , PHP .

I have done my fair amount of hacking PHP applications. In that time, I have come across many poor programming practices that have caused me to almost lose my mind. One that really grinds my gears is overuse of global variables.


function myFunction()
{
  global $config1, $status1, $object1;

if ($config1 === true) {
$object1->doSomething();
} else {
if (!$status1) {
$object1->doSomethingElse();
$status1 = true;
} else {
$object1->doAnotherThing();
}
}
}

If you are like me, code like the above drives you up a wall. The reason? The use of global variables was unjustified because better alternatives are available. The purpose of this entry is to explain why global variables are unjustified and what some alternatives are.

First, we need to recognize that there are multiple types of global variables. Well, not technically (a PHP variable is a variable; it can be any type you want). Global variables can be distinguished by the type functionality they provide. I identify three types of global variables: Configuration Settings, Status Variables, and Global Objects

Configuration Settings

The configuration setting global variable is a supposedly read-only variable used to dictate system-wide behavior. Configuration variables should never change when a program executes. Configuration setting variables are the least dangerous of the three types of global variables because the usage of a global variable to pass configuration information more or less makes sense. The downside to using global configuration variables is that they can be modified from anywhere in the program. Configuration settings should be read-only. All it takes is one unknowing programmer...

The solution to global configuration settings? A static class instance holding all of the configuration settings. I recommend Zend Framework's Zend_Config as the answer to the later part of that solution. I use the Zend Registry to store an instance of my config object. From any function in my program, I can just write


  if (Zend::registry('config')->setting1) {
    //do something
  }
Note: In practice, I usually abstract the call to Zend::registry() in case I ever have a need to change which set of config variables I am using.

Want another reason to use Zend_Config? It defaults to not allowing modifications of variables. Perfect for configuration settings!

Status Variables

Status variables are used to keep track of something during the course of a program's execution. Whatever it is you are tracking you may need to access in multiple functions. It is painful to keep passing the same variable to these functions, so you figure a global variable is the best solution. For applications using the procedural design approach, I can see the argument for using global status variables. However, the second you move to OOP, it becomes poor programming practice.

How do you solve the problem of global status variables? Object oriented programming. Good object oriented programming allows you to bury status variables as parts of objects. When a function is accessed, it looks at its internal status and reacts accordingly. Why should your addRecord() function check to see if there is a database connection? Your addRecord() function should just call $database->doQuery() and the database worries about establishing the connection. This probably sounds obvious to many, but you wouldn't believe how many times I have seen it in popular open source applications.

Global Objects


function myFunction()
{
  global $myObject;
  $myObject->doSomething();
}

Whenever I see code like the above, my stomach feels queezy, especially when I see this reference inside a class method. The reason is that dependence on global object instances limits the flexibility of your program. I hate to single out applications, but here I must in order to illustrate my point. MediaWiki, the software that powers Wikipedia, is notorious for using global objects. In MediaWiki, the OutputPage class is an object used to build content for a page. Class methods for OutputPage have dependencies on global objects, like $wgParser, which is the globally-registered parser object. Whenever you call the parse() method on the OutputPage object to convert wikitext to HTML, $wgParser is referenced and its settings are applied. The problem with this approach is it is nearly impossible to have two instances of the OutputPage class with each using its own parser settings. Unfortunately, the problem exists in almost every class in MediaWiki, making extending the program beyond its traditional functionality almost impossible.

Having objects depend on global objects is just plain dumb and should be avoided at all costs. So, how do you avoid this? One method is to make an object self-sufficient. Once an object is instantiated, it should not depend on any global variable, except perhaps a constant configuration setting. In your class contructor, copy the globally-referenced objects to member variables of your class. Do not rely on global variables after contruction. However, this is just a hack. You will eventuallly find the need for this proposterous coding pattern:


$oldValue = $GLOBALS['object'];
$GLOBALS['object'] = new MyObject();

$instance2 = new MyOtherObject();
$GLOBALS['object'] = $oldValue;


Horrific, isn't it?

The real solution is for your objects to not depend on any global objects at all. Anything that affects the behavior of an object should be passed to the constructor. Plain and simple. When designing a program, especially one that allows people to write their own plugins and extensions, it is imperative that there be no global object dependencies, because you never know how someone may extend the application. Plan for the unexpected and don't lock yourself into allowing only one type of behavior.

After all of that, some of you are still saying that there are times when there only needs to be one instance of a particular object (say a class representing the browser request) and it is OK to use global variables. You would be correct, but only if the static keyword and the Singleton pattern it makes possible didn't exist. The Singleton pattern can be a very powerful tool in these situations. If you will only ever need one instance of an object across your whole program, then the Singleton pattern is the way to go.

In summary, you should avoid using global variables because they limit program flexibility and their functionality can be duplicated using methods that are more aptly suited for the task at hand. If you are still not convinced that global variables in PHP is bad, I recommend querying your favorite search engine for "PHP global variable" and reading all the security-related problems that arise from poor use of global variables.

Trackback

You can ping this entry by using http://blog.case.edu/gps10/mt-tb.cgi/8959 .

Comments

http://blog.case.edu/gps10/2005/09/02/case_iptv_coming_to_the_linux_desktop


http://blog.case.edu/gps10/2005/11/21/disappointed_with_ostn


http://wiki.case.edu/Iptv


Instead of utterly stupid removing all comments at this blog, you should answer.

The stream links donĀ“t work directly anymore, any new direct links?

Posted by blogcomment at July 24, 2006 04:05 AM

Perhaps the streams are only available if you are on campus. I have no clue why they don't work anymore. The URL's were possibly updated. Anybody at Case can find the new streams by going to http://my.case.edu

Posted by Someone at July 24, 2006 11:07 AM

Thanks for these hints. I apreciate it very much, because improving programmer style is always important. The momnet I was typing "global" inside a class method I got suspicious and wondered about where to find some comments about this. A short google led me to your site...

Posted by Derni at July 26, 2006 10:07 AM

Great work!
[url=http://emybwlzm.com/qkxg/xirs.html]My homepage[/url] | [url=http://updroitr.com/dwwq/xtdk.html]Cool site[/url]

Posted by Pamela at July 27, 2006 03:03 AM

Good design!
My homepage | Please visit

Posted by Don at July 27, 2006 03:07 AM

Well done!
http://emybwlzm.com/qkxg/xirs.html | http://shhiumqy.com/gyut/clms.html

Posted by Jill at July 27, 2006 03:08 AM

anal sex galleries homemade anal

Posted by Rptsfs at October 9, 2006 02:45 AM

Thanks! Your article helps to answer the question I had. I know registered_global is bad but I wasn't sure about making global variables using the global keyword.

I suppose good programming practice is to use setter and getter methods for accessing public variables in an object.

Posted by Lawrence at November 23, 2006 01:41 PM

The Rolling Stones cancel a gig in Hawaii and postpone other tour dates as Mick Jagger suffers throat troubles...

Posted by Zavier Sam at November 23, 2006 07:52 PM

Colombia's vice president is "baffled" by Kate Moss's success following cocaine allegations...

Posted by Frederick Leggett at November 24, 2006 01:53 AM

Veteran actor William Franklyn, known for voicing the 1960s Schweppes TV adverts, dies aged 81...

Posted by Dane Guerrero at December 13, 2006 04:20 PM

Great article.

Posted by Cheap Web Host at January 12, 2007 10:38 PM

Post a comment










Remember personal info?