103

According to the most programming languages scope rules, I can access variables that are defined outside of functions inside them, but why doesn't this code work?

<?php
    $data = 'My data';

    function menugen() {
        echo "[" . $data . "]";
    }

    menugen();
?>

The output is [].

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Amin Gholibeigian
  • 1,325
  • 2
  • 9
  • 11
  • 3
    Don't treat it as global, pass it to the function as an argument – Mark Baker Mar 28 '13 at 16:38
  • 2
    Where does the manual say such things? – deceze Mar 28 '13 at 16:39
  • Related reading: [PHP global in functions](http://stackoverflow.com/q/5166087/1409082) – Jocelyn Mar 28 '13 at 16:42
  • Check the second example in this page : http://php.net/manual/en/language.variables.scope.php – Amin Gholibeigian Mar 28 '13 at 16:46
  • afaik we can access using $GLOBALS['varname'] where the index "varname" is $varname outside the function.Infact we can use print_r($GLOBALS) to view all the global variables. – Ahmad Jan 07 '15 at 17:57
  • @MarkBaker Not always the best approach. Consider a simple script with a few loose functions and some shared variables outside of them. Changing how your functions work or putting everything in classes and using `$this->foo` can be overkill. – Beejor Aug 21 '16 at 03:38
  • 1
    @MarkBaker My pet peeve is that when an asker want to do X, people reply "don't do X" instead of answering the question. when the asker decides to do X, we should presume innocence and think that the asker has been thinking this thoroughly. – Xwtek May 23 '20 at 04:06
  • Largely related to: [Callback function using variables calculated outside of it](https://stackoverflow.com/q/4588714/2943403) – mickmackusa Mar 25 '23 at 06:59

10 Answers10

197

To address the question as asked, it is not working because you need to declare which global variables you'll be accessing in the function itself:

$data = 'My data';

function menugen() {
    global $data; // <-- Add this line

    echo "[" . $data . "]";
}

menugen();

Otherwise you can access it as $GLOBALS['data'], see Variable scope.

Even if a little off-topic, I would suggest you avoid using globals at all and prefer passing data as parameters.

In this case, the above code look like this:

$data = 'My data';

function menugen($data) { // <-- Declare the parameter
    echo "[" . $data . "]";
}

menugen($data); // <-- And pass it at call time
Matteo Tassinari
  • 18,121
  • 8
  • 60
  • 81
  • Thanks , You are right but they didn't use this line in the second example of manual :http://php.net/manual/en/language.variables.scope.php – Amin Gholibeigian Mar 28 '13 at 18:46
  • 6
    In fact that second example was there to show the readers what **not** to do: `This script will not produce any output because the echo statement refers to a local version of the $a variable, and it has not been assigned a value within this scope.` – Matteo Tassinari Mar 29 '13 at 14:44
  • 3
    Dang! I had to login to upvote this answer just because i creepily forgot php variables scoping. – Milche Patern Dec 03 '15 at 15:32
23

You can do one of the following:

<?php
    $data = 'My data';

    function menugen() {
        global $data;
        echo "[" . $data . "]";
    }

    menugen();

Or

<?php
    $data = 'My data';

    function menugen() {
        echo "[" . $GLOBALS['data'] . "]";
    }

    menugen();

That being said, overuse of globals can lead to some poor code. It is usually better to pass in what you need. For example, instead of referencing a global database object you should pass in a handle to the database and act upon that. This is called dependency injection. It makes your life a lot easier when you implement automated testing (which you should).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jcbwlkr
  • 7,789
  • 2
  • 22
  • 28
18

Another way to do it:

<?php

$data = 'My data';

$menugen = function() use ($data) {

    echo "[".$data."]";
};

$menugen();

UPDATE 2020-01-13: requested by Peter Mortensen

As of PHP 5.3.0 we have anonymous functions support that can create closures. A closure can access the variable which is created outside of its scope.

In the example, the closure is able to access $data because it was declared in the use clause.

donvercety
  • 221
  • 2
  • 7
  • 1
    This was the only working solution in my case, where I had a function defined as a variable inside another function. Global didn't work there. – Kar.ma Jun 04 '19 at 16:30
  • An explanation would be in order. E.g., what does this "use" thingy do? What PHP versions are this "use" thingy supported in? (Please respond by [editing your answer](https://stackoverflow.com/posts/35233003/edit), not here in comments (as appropriate). Thanks in advance.) – Peter Mortensen Dec 18 '19 at 17:30
  • Don't know why the approved ans doesn't show any output in Wordpress admin plugin page but this ans does work well. – Naimur Hasan Aug 28 '20 at 21:26
13

It's a matter of scope. In short, global variables should be avoided so:

You either need to pass it as a parameter:

$data = 'My data';

function menugen($data)
{
    echo $data;
}

Or have it in a class and access it

class MyClass
{
    private $data = "";

    function menugen()
    {
        echo this->data;
    }

}

See @MatteoTassinari answer as well, as you can mark it as global to access it, but global variables are generally not required, so it would be wise to re-think your coding.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
webnoob
  • 15,747
  • 13
  • 83
  • 165
  • and another way is to use the keyword **global** (granted, this is not the best way). – Jocelyn Mar 28 '13 at 16:41
  • 2
    "Should" doesn't answer the question, and this may not be the best approach for every case. For simple scripts, changing parameters around and adding classes is clunky. Much like JavaScript, in PHP not everything needs to be object-oriented and namespaced up the wazoo. – Beejor Aug 21 '16 at 03:44
  • @Beejor Given that the OP has a function called `menugen()` it implies there is going to be more going than simply generating a menu. For instance, what about extending that menu to add more items from a different source, what about selecting the currently selected page that's in the menu. Having random global vars and logic all over the place screams for OOP design. The fact that PHP / JS doesn't need to be structured is one of the biggest reasons you find lots of messy clunky code. It can be done very well but allows people to have no thought about maintainability going forward. – webnoob Aug 21 '16 at 14:49
  • p.s Down voting the answer is also a bit off. The answer does provide a solution to the OP's problem, just because you don't like it, doesn't make it wrong. – webnoob Aug 21 '16 at 14:51
  • 1
    It may provide a solution for an implied problem, but doesn't really answer the original question, which was how to access a global variable in a function. And which is how people land on this page from web searches. – Beejor Aug 26 '16 at 10:12
  • 2
    @Beejor - The problem with that argument is that people might *think* they need a global variable because they don't know any better and won't know any better unless they are told. – webnoob Aug 26 '16 at 19:59
5

For many years I have always used this format:

<?php
    $data = "Hello";

    function sayHello(){
        echo $GLOBALS["data"];
    }

    sayHello();
?>

I find it straightforward and easy to follow. The $GLOBALS is how PHP lets you reference a global variable. If you have used things like $_SERVER, $_POST, etc. then you have reference a global variable without knowing it.

Psalms Kalu
  • 95
  • 1
  • 5
  • Which one? `$GLOBAL` (text) or `$GLOBALS` (sample code)? (Please respond by [editing your answer](https://stackoverflow.com/posts/57667224/edit), not here in comments (as appropriate).) – Peter Mortensen Dec 18 '19 at 17:39
  • it's $GLOBALS not $GLOBAL. There should be an "S". Then reference your variable name like a key to an associative array. – Psalms Kalu Jan 08 '20 at 20:10
  • Please [update your answer by editing it](https://stackoverflow.com/posts/57667224/edit) (to start [the editing](https://stackoverflow.com/posts/57667224/edit), click on *"[edit](https://stackoverflow.com/posts/57667224/edit)"*, between *"share"* and *"flag"*. Those three are on the left - to the left of *"edited"* and *"answered"*, after the answer itself, above this comment, and above all three comments here). Information in comments can disappear at any moment. This is *not* a forum - information ***can (and should be) updated*** here. Thank you very much indeed in advance. – Peter Mortensen Jan 24 '20 at 18:58
1

I was looking for this answer, sort of, I wanted to see if anyone else had something similar with respect to how $prefix would be passed to an anonymous function. Seems the global scope is the the way? This is my solution for prefixing an array in a non-destructive manner.

private function array_prefix($prefix, $arr) {
  $GLOBALS['prefix'] = $prefix;
  return array_map(
    function($ele) {
      return $GLOBALS['prefix'].$ele;
    },
    $arr
  );
}
Bob Smith
  • 145
  • 5
1

The proper way for accessing a global variable inside a function is answered above!

BUT if you do not want to use the global keyword, nor the $GLOBALS variable for some reason (for example you have multiple functions and you are "tired" of writing global $variable; every time), here is a workaround:

$variable = 42;  // the global variable you want to access

// write a function which returns it
function getvar(){ 
    global $variable; 
    return $variable; 
}

//--------------

function func1()
{
    // use that getter function to get the global variable
    echo getvar();  // 42
}

function func2()
{
    echo getvar();  // 42
}
...
hlorand
  • 1,070
  • 10
  • 8
0
<?php

    $data = 'My data';

    $menugen = function() use ($data) {

        echo "[ $data ]";
    };

    $menugen();
?>

You can also simplify

echo "[" . $data . "]"

to

echo "[$data]"
Sanjeev Budha
  • 49
  • 1
  • 9
0

PHP can be frustrating for this reason. The answers above using global did not work for me, and it took me awhile to figure out the proper use of use.

This is correct:

$functionName = function($stuff) use ($globalVar) {
 //do stuff
}
$output = $functionName($stuff);
$otherOutput = $functionName($otherStuff);

This is incorrect:

function functionName($stuff) use ($globalVar) {
 //do stuff
}
$output = functionName($stuff);
$otherOutput = functionName($otherStuff);

Using your specific example:

    $data = 'My data';

    $menugen = function() use ($data) {
        echo "[" . $data . "]";
    }

    $menugen();
-3

You need to pass the variable into the function:

$data = 'My data';

function menugen($data)
{
    echo $data;
}
Major Productions
  • 5,914
  • 13
  • 70
  • 149