Claudiu Persoiu

Blog-ul lui Claudiu Persoiu


PHP 5.4 – Closures the right way!

with 5 comments

The concept of closure was introduced in PHP 5.3, with the new “more traditional” syntax for anonymous functions.

PHP 5.3

In PHP 5.3, a closure will rely on the term “use”, which was passing the variables to the anonymous function, making it a closure.

The problem is that the anonymous function will only be able to access the variables that have been passed with “use”. When it comes to objects, there are passed by reference by default, but scalar variables (int, string, etc.) are passed by value, as this is the default behavior in PHP 5+:

$scalar = 5;

$closure = function () use ($scalar) {
     return 'Scalar: ' . $scalar . PHP_EOL;
};

echo $closure(); // Scalar: 5

$scalar = 7;

echo $closure(); // Scalar: 5

Another problem is that you cannot pass $this when the anonymous function is declared inside an object, so only the public method and properties can be accessed inside the closure.

PHP 5.4

In PHP 5.4 the keyword “use” is optional, and the entire environment where the function was created is available inside the function.

The advantage is that when the anonymous function is created inside another function or method, the anonymous function has access to the environment where it was created, even after the execution of the environment is over. The objects from this environment will be unset, only after the last reference to the closure will be unset:

class testClass {

        private $changeableVar = 1;
        private $bigVar;

        public function __construct() {
                // Allocate a big variable so we can see the changes in memory
                $this->bigVar = str_repeat("BigWord", 5000);
        }

        /**
         * A method that returns the closure
         */
        public function closure() {

                return function () {
                        // Display the value of a private property of the object
                        echo 'Private property: ' . $this->changeableVar.PHP_EOL;

                        // Change the value of a private property of the object
                        $this->changeableVar = 2;
                };
        }

        /**
         * Method that displays a private property
         */
        public function showChangeableVar() {
                echo 'Private property in method: ' . $this->changeableVar.PHP_EOL;
        }

}

// Memory befor the objects is created
echo "Memory: " . memory_get_usage() . PHP_EOL; // Memory: 229896

// Create object
$testObj = new testClass();

// Create closure
$closure = $testObj->closure();

// Execute closure
$closure(); // Private property: 1

// Displaying the current value of the private property
$testObj->showChangeableVar(); // Private property in method: 2

// Memory befor object will be unset
echo "Memory: ". memory_get_usage() . PHP_EOL; // Memory: 266240

// Unset the object
unset($testObj);

// Memory after the object was distroyed, there is no big difference in memory
echo "Memory: ". memory_get_usage() . PHP_EOL; // Memory: 266152

// Run closure after the object in which it was created was unset
echo $closure(); // Private property: 2

// Unset closure and with it the object environment
unset($closure);

// Memotry after the las reference to the object (closure) is unset
echo "Memory: " . memory_get_usage() . PHP_EOL; // Memory: 230416

Callable type hinting

Another new feature introduced in PHP 5.4 regarding closures is the new “type hint”: “callable”. Actually callable is referring to any anonymous function, and even to a new way of calling a method of an object:

<?php

// A function that uses type hinting
function typeHinting(callable $a) {
     echo $a() . PHP_EOL;
}

// A closure
$closure = function () {
     return __FUNCTION__;
};

// Call the type hinting function with the closure
typeHinting($closure); // {closure}

class testClass {
     public function testMethod() {
          return __METHOD__;
     }
}

// A mock object
$testObj = new testClass();

// The new way of calling object methods
$objCallable = array($testObj, 'testMethod');

// Call type hinting function with the new method calling way
typeHinting($objCallable); // testClass::testMethod

I believe that only now we can really say that PHP supports closures, the right way!

Written by Claudiu Persoiu

11 February 2012 at 5:10 PM

Posted in PHP

Tagged with , , , ,

5 Responses to 'PHP 5.4 – Closures the right way!'

Subscribe to comments with RSS or TrackBack to 'PHP 5.4 – Closures the right way!'.

  1. In PHP 5.4 the keyword “use” is no longer necessary, and the entire environment where the function was created is available inside the function.

    This is not true. The `use` keyword is still required to pull local variables into the closure’s scope. Only `$this` is automatically inherited by the closure, and only when the closure is defined in the scope of an instance method.

    Dan

    20 October 2013 at 10:14 PM

  2. I’m not saying is not “available”, is just not required like before. Before you had to use it if you wanted any context at all, but now is more a matter of opinion.

    A good remark, maybe I should change my formulation.

    Claudiu Persoiu

    20 October 2013 at 11:16 PM

  3. Nu mergea sintaxa function () use ( & $scalar) ?

    Bogdan

    9 March 2014 at 7:12 AM

  4. Nu inteleg, la ce te referi?

    Claudiu Persoiu

    9 March 2014 at 9:52 AM

Leave a Reply