We can illustrate this problem with the following pseudo-code
function foo() {
global $bob;
$bob->doSomething();
}
Your first question here is an obvious one
Where did
$bob
come from?
Are you confused? Good. You've just learned why globals are confusing and considered a bad practice.
If this were a real program, your next bit of fun is to go track down all instances of $bob
and hope you find the right one (this gets worse if $bob
is used everywhere). Worse, if someone else goes and defines $bob
(or you forgot and reused that variable) your code can break (in the above code example, having the wrong object, or no object at all, would cause a fatal error).
Since virtually all PHP programs make use of code like include('file.php');
your job maintaining code like this becomes exponentially harder the more files you add.
Also, this makes the task of testing your applications very difficult. Suppose you use a global variable to hold your database connection:
$dbConnector = new DBConnector(...); function doSomething() { global $dbConnector; $dbConnector->execute("..."); }
In order to unit test this function, you have to override the global $dbConnector
variable, run the tests and then reset it to its original value, which is very bug prone:
/** * @test */ function testSomething() { global $dbConnector; $bkp = $dbConnector; // Make backup $dbConnector = Mock::create('DBConnector'); // Override assertTrue(foo()); $dbConnector = $bkp; // Restore }
How do we avoid Globals?
The best way to avoid globals is a philosophy called Dependency Injection. This is where we pass the tools we need into the function or class.
function foo(\Bar $bob) {
$bob->doSomething();
}
This is much easier to understand and maintain. There's no guessing where $bob
was set up because the caller is responsible for knowing that (it's passing us what we need to know). Better still, we can use type declarations to restrict what's being passed.
So we know that $bob
is either an instance of the Bar
class, or an instance of a child of Bar
, meaning we know we can use the methods of that class. Combined with a standard autoloader (available since PHP 5.3), we can now go track down where Bar
is defined. PHP 7.0 or later includes expanded type declarations, where you can also use scalar types (like int
or string
).
Superglobal variables
Super globals in PHP are predefined variables, which are always available, can be accessed from any scope throughout the script.
There is no need to do global $variable; to access them within functions/methods, classes or files.
These PHP superglobal variables are listed below: