Repox Repox - 1 year ago 83
PHP Question

Access variables from the global scope within a closure

I am well aware that globals are evil and this is an issue I will deal with later. It's not my codebase, but I've been assigned some cleaning up tasks.

Trying to smarten up a codebase, I decided to implement simple routing by using a package known as AltoRouter - I've worked with it before and it has worked fine for my purposes.

Now, the codebase is using a large amount of variables declared in the global scope. Usually, these variables are then fetched by using the

keyword. But for some reason, this doesn't work when I'm working inside a closure.

Consider this simple routing example:

require 'vendor/autoload.php';
$router = new AltoRouter();

$router->map('GET', '/shops/[i:id]', function($id) {

$_GET['shop_id'] = $id;
require 'go_to_shop.php';

$match = $router->match();

if( $match && is_callable( $match['target'] ) ) {
call_user_func_array( $match['target'], $match['params'] );

This calls my closure that sets a variable and requires a file.

This produces an error:

Fatal error: Call to a member function get() on null in
/vagrant/Core/CampaignHandler.php on line 71

Now, the code being called doing this is the following (line 70-71):

// Inside a method
global $serviceContainer;
$dispatcher = $serviceContainer->get("dispatcher");

is being declared by including a file early on:

$serviceContainer = new ServiceContainer();
$serviceContainer->set("dispatcher", new EventDispatcher());

Basically, if I move the contents of the closure outside of the closure, everything works perfectly - but as soon as I'm doing it from inside the closure, all variables accessed via the global scope is empty - and I have no idea as to why.

I've tried using
on the closure, this didn't work either.

I'm mostly looking for an explanation rather than a solution.

Answer Source

Globals are evil for a reason. You get the error because the global is not initialized at the time when function is being called. The mess of globals and requires is the exact issue and you are already trying to deal with it.

There is no problem to use globals in closure per se. This example works perfectly fine:


class Foo {
    public function bar() { return 'bar';}

$foo = new Foo;


require 'global.php';

$test = function($param) {
    global $foo;
    echo $param, $foo->bar();

call_user_func_array($test, ['baz']);

so php test.php outputs bazbar;

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download