Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP global in functions

What is the utility of the global keyword?

Are there any reasons to prefer one method to another?

  • Security?
  • Performance?
  • Anything else?

Method 1:

function exempleConcat($str1, $str2) {   return $str1.$str2; } 

Method 2:

function exempleConcat() {   global $str1, $str2;   return $str1.$str2; } 

When does it make sense to use global?

For me, it appears to be dangerous... but it may just be a lack of knowledge. I am interested in documented (e.g. with example of code, link to documentation...) technical reasons.

Thanks in advance!


Bounty

This is a nice general question about the topic, I (@Gordon) am offering a bounty to get additional answers. Whether your answer is in agreement with mine or gives a different point of view doesn't matter. Since the global topic comes up every now and then, we could use a good "canonical" answer to link to.

like image 380
Pascal Qyy Avatar asked Mar 02 '11 10:03

Pascal Qyy


People also ask

Can I use global variable in function PHP?

Global variables can be accessed from any part of the script i.e. inside and outside of the function. So, a global variable can be declared just like other variable but it must be declared outside of function definition.

Are all PHP variables global?

PHP also stores all global variables in an array called $GLOBALS[index] . The index holds the name of the variable. This array is also accessible from within functions and can be used to update global variables directly.

What is global keyword in PHP?

The global keyword imports variables from the global scope into the local scope of a function.


Video Answer


1 Answers

Globals are evil

This is true for the global keyword as well as everything else that reaches from a local scope to the global scope (statics, singletons, registries, constants). You do not want to use them. A function call should not have to rely on anything outside, e.g.

function fn() {     global $foo;              // never ever use that     $a = SOME_CONSTANT        // do not use that     $b = Foo::SOME_CONSTANT;  // do not use that unless self::     $c = $GLOBALS['foo'];     // incl. any other superglobal ($_GET, …)     $d = Foo::bar();          // any static call, incl. Singletons and Registries } 

All of these will make your code depend on the outside. Which means, you have to know the full global state your application is in before you can reliably call any of these. The function cannot exist without that environment.

Using the superglobals might not be an obvious flaw, but if you call your code from a Command Line, you don't have $_GET or $_POST. If your code relies on input from these, you are limiting yourself to a web environment. Just abstract the request into an object and use that instead.

In case of coupling hardcoded classnames (static, constants), your function also cannot exist without that class being available. That's less of an issue when it's classes from the same namespace, but when you start mix from different namespaces, you are creating a tangled mess.

Reuse is severly hampered by all of the above. So is unit-testing.

Also, your function signatures are lying when you couple to the global scope

function fn() 

is a liar, because it claims I can call that function without passing anything to it. It is only when I look at the function body that I learn I have to set the environment into a certain state.

If your function requires arguments to run, make them explicit and pass them in:

function fn($arg1, $arg2) {     // do sth with $arguments } 

clearly conveys from the signature what it requires to be called. It is not dependent on the environment to be in a specific state. You dont have to do

$arg1 = 'foo'; $arg2 = 'bar'; fn(); 

It's a matter of pulling in (global keyword) vs pushing in (arguments). When you push in/inject dependencies, the function does not rely on the outside anymore. When you do fn(1) you dont have to have a variable holding 1 somewhere outside. But when you pull in global $one inside the function, you couple to the global scope and expect it to have a variable of that defined somewhere. The function is no longer independent then.

Even worse, when you are changing globals inside your function, your code will quickly be completely incomprehensible, because your functions are having sideeffects all over the place.

In lack of a better example, consider

function fn() {     global $foo;     echo $foo;     // side effect: echo'ing     $foo = 'bar';  // side effect: changing } 

And then you do

$foo = 'foo'; fn(); // prints foo fn(); // prints bar <-- WTF!! 

There is no way to see that $foo got changed from these three lines. Why would calling the same function with the same arguments all of a sudden change it's output or change a value in the global state? A function should do X for a defined input Y. Always.

This gets even more severe when using OOP, because OOP is about encapsulation and by reaching out to the global scope, you are breaking encapsulation. All these Singletons and Registries you see in frameworks are code smells that should be removed in favor of Dependency Injection. Decouple your code.

More Resources:

  • http://c2.com/cgi/wiki?GlobalVariablesAreBad
  • How is testing the registry pattern or singleton hard in PHP?
  • Flaw: Brittle Global State & Singletons
  • static considered harmful
  • Why Singletons have no use in PHP
  • SOLID (object-oriented design)
like image 117
Gordon Avatar answered Sep 19 '22 11:09

Gordon