Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scope of variables with a function within a function?

In Python you can have the following:

def foo(param1, param2):
    def bar():
        print param1 + param2
    bar()

I am having some difficulties with this behaviour in PHP though. I expect this to work in the following way:

function foo($param1, $param2)
{
    function bar()
    {
        echo $param1 + $param2;
    }
    bar();
}

But that fails. So I read some about closures (this is called a closure is it not? It is in Python, that I know). And in the php documentation about anonymous functions (which they said to have been implemented as closures) they tell you to use the use() expression in the following manner:

function foo($param1, $param2)
{
    function bar() use($param1, $param2)
    {
        echo $param1 + $param2;
    }
    bar();
}

But that still fails. So I changed it to the PHP-anonymous function a-like like this:

function foo($param1, $param2)
{
    $bar = function() use($param1, $param2)
    {
        echo $param1 + $param2;
    };
    $bar();
}

That does work, however it just looks really ugly. Am I missing something? Can I improve this in any way? Or will I just have to use the 'ugly' way?

(I am not looking for a discussion about if closures are useful)

like image 415
Daan Timmer Avatar asked Jun 01 '12 14:06

Daan Timmer


2 Answers

I couldn't find the function bar() use($param1, $param2) syntax on the manual page you linked to, just the "ugly" version that works (which is truly anonymous). I guess you'll have to use that.

On your second example, bar is not a closure. To create a closure in PHP you have to use the ugly use, or the Closure class. Every function will create its own local scope, but closures are not automatic.

PHP seems to have an odd definition for the term "closure", as you probably noted when you read the manual. They define it as a synonym for "anonymous function":

Anonymous functions, also known as closures (...)

Confusing, right? Later, they explain you need the use keyword if you want to inherit the parent scope:

Closures may also inherit variables from the parent scope. Any such variables must be declared in the function header.

The PHP Wiki rfc page on closures gives us some hints on why closures were implemented this way:

PHP's notion of scope is quite different than the notion of scope other languages define. Combine this with variable variables ($$var) and it becomes clear that automatically detecting which variables from the outer scope are referenced inside are closure is impossible. Also, since for example global variables are not visible inside functions either by default, automatically making the parent scope available would break with the current language concept PHP follows.

like image 121
bfavaretto Avatar answered Sep 24 '22 02:09

bfavaretto


In PHP, you can't access intermediate scopes. You only have your local scope, and the global scope. This is an artefact of the perverse scope rules of PHP, which are the complete opposite of any sane language's scope rules.

like image 21
lanzz Avatar answered Sep 23 '22 02:09

lanzz