7

I'm using PHP 5.4 and wondering if the anonymous functions I'm making have lexical scoping?

I.e. If I have a controller method:

protected function _pre() {
    $this->require = new Access_Factory(function($url) {
        $this->redirect($url);
    });
}

When the Access Factory calls the function it was passed, will the $this refer to the Controller where it was defined?

Charles
  • 1,029
  • 1
  • 11
  • 15

2 Answers2

7

Anonymous functions don't use lexical scoping, but $this is a special case and will automatically be available inside the function as of 5.4.0. Your code should work as expected, but it will not be portable to older PHP versions.


The following will not work:

protected function _pre() {
    $methodScopeVariable = 'whatever';
    $this->require = new Access_Factory(function($url) {
        echo $methodScopeVariable;
    });
}

Instead, if you want to inject variables into the closure's scope, you can use the use keyword. The following will work:

protected function _pre() {
    $methodScopeVariable = 'whatever';
    $this->require = new Access_Factory(function($url) use ($methodScopeVariable) {
        echo $methodScopeVariable;
    });
}

In 5.3.x, you can get access to $this with the following workaround:

protected function _pre() {
    $controller = $this;
    $this->require = new Access_Factory(function($url) use ($controller) {
        $controller->redirect($url);
    });
}

See this question and its answers for more details.

Community
  • 1
  • 1
Matt Kantor
  • 1,704
  • 1
  • 19
  • 37
  • Ah, good to know it's different in PHP5.4 (which still hasn't reached my Debian Stable packages yet... might need to install it manually). – Wrikken May 03 '13 at 17:32
  • Do I need a "use ($this)" or does 5.4 automatically give you access to $this? – Charles May 03 '13 at 17:42
  • 5.4.0+ automatically binds `$this`. Check out [this short video](http://youtu.be/-Ph7X6Y6n6g) explaining it. – Matt Kantor May 03 '13 at 17:43
  • Of course it uses lexical scoping. Every programming in common use today uses lexical scoping. `$this` is a special variable and has special meaning. – newacct May 04 '13 at 06:39
  • 2
    @newacct: In PHP functions are not lexically [scoped](http://php.net/manual/en/language.variables.scope.php), at least not according the definition of that term which I'm familiar with. They're "sealed off" from surrounding scopes and can only access or affect variables inside themselves, (super)globals, and `$this`/`self`/`parent` (if defined within a class), unless extra variables are explicitly bound with `use`. See [this demo](http://phpfiddle.org/lite/code/5518331). – Matt Kantor May 04 '13 at 20:05
  • Yeeeech, selective closure! What a ghastly concept. Someone in PHPland should be shot. – Beetroot-Beetroot May 05 '13 at 13:39
1

In short, no, but you can access public methods & functions by passing it:

$that = $this;
$this->require = new Access_Factory(function($url) use ($that) {
    $that->redirect($url);
});

edit: as Matt rightly pointed out support for $this in closures started with PHP 5.4

Wrikken
  • 69,272
  • 8
  • 97
  • 136