Closures in PHP5.4 alpha

The PHP community has been on a roll lately, after the great new release of PHP5.3 last year, a shiny new alpha is seeing light aka PHP5.4. The featurelist is not as big as the one of the previous release. But that’s because the previous one was huge… sporting stuff like namespaces, anonymous functions and late static binding.
PHP5.4 is mostly aimed at improving the previous release, but also gives us devs some nice features to enhance our codebase. most notable are:

  • addition of Traits
  • array dereferencing support
  • $this support in closures
  • indirect method call through an array

All of these might one day get an article, if I manage to do some testing, but for now I’ve only tested the closure enhancements. And with some unexpected results.

If one would create a closure inside a class, PHP5.4 will put that closure inside the same scope as a regular class method. This does not only make $this available inside the closure, but you can also access protected and private methods of said class.
I’ve put a little script together to test this:

<?php
class Test {
    public function testAccess()
    {
        echo PHP_EOL.'-- testing access from within class function '.PHP_EOL;
        $this->testPublic();
        $this->testProtected();
        $this->testPrivate();
        echo PHP_EOL;
    }

    public function getClos() {
        return function ($val) {
            echo PHP_EOL.'== Test from within closure'.PHP_EOL;
            echo $val.PHP_EOL;
            var_dump($this);
            $this->testPublic();
            $this->testProtected();
            $this->testPrivate();
            echo PHP_EOL;
        };
    }

    public function testPublic()
    {
        echo 'can access Public!'.PHP_EOL;
    }

    protected function testProtected()
    {
        echo 'can access Protected!'.PHP_EOL;
    }

    private function testPrivate()
    {
        echo 'can access private!'.PHP_EOL;
    }
}

class TestInher extends Test {
    public function testAccess()
    {
        echo PHP_EOL.'-- testing access from within class function '.PHP_EOL;
        $this->testPublic();
        $this->testProtected();
        $this->testPrivate();
        echo PHP_EOL;
    }

    public function testPublic()
    {
        echo 'accessing the overridden public function'.PHP_EOL;
    }
}

$test = new Test;
$test->testAccess();
$clos = $test->getClos();
$clos('testing closure');

$testInher = new TestInher;
$testInher->testAccess();
$clos = $testInher->getClos();
$clos('testing closure from inherited class');

Now as you would expect, line 46 will fail, because an inherited class can not access a private method of a parent. This is the output of the script with line 46 commented out:

-- testing access from within class function
can access Public!
can access Protected!
can access private!

== Test from within closure
testing closure
object(Test)#1 (0) {
}
can access Public!
can access Protected!
can access private!

-- testing access from within class function
accessing the overridden public function
can access Protected!

== Test from within closure
testing closure from inherited class
object(TestInher)#3 (0) {
}
accessing the overridden public function
can access Protected!
can access private!

The most notable lines here are 20 and 24. The former stating that $this is an object of type ‘TestInher’, but the latter $this->testPrivate() does not result in an error!
I do not know if this was intended behaviour, but will check this through the appropriate channels, an update will follow.

All in all this is a very neat improvement, that I am sure will please lots of devs, me included.

[UPDATE]

After looking at the code again I realised it’s just intended behavior, as it would be exactly the same thing as adding this method to class Test:

    public function sameAsClosure()
    {
        echo PHP_EOL.'== Test from within sameAsClosureFunction'.PHP_EOL;
        echo $val.PHP_EOL;
        var_dump($this);
        $this->testPublic();
        $this->testProtected();
        $this->testPrivate();
        echo PHP_EOL;
    }

From inside the scope of the parent class we can access its private methods, and if we were to extends it, we can also call the public sameAsClosure() method from any scope.