Closures in PHP... what, precisely, are they and when would you need to use them?

PhpOopClosures

Php Problem Overview


So I'm programming along in a nice, up to date, object oriented fashion. I regularly make use of the various aspects of OOP that PHP implements but I am wondering when might I need to use closures. Any experts out there that can shed some light on when it would be useful to implement closures?

Php Solutions


Solution 1 - Php

PHP will support closures natively in 5.3. A closure is good when you want a local function that's only used for some small, specific purpose. The RFC for closures gives a good example:

function replace_spaces ($text) {
    $replacement = function ($matches) {
        return str_replace ($matches[1], ' ', ' ').' ';
    };
    return preg_replace_callback ('/( +) /', $replacement, $text);
}

This lets you define the replacement function locally inside replace_spaces(), so that it's not:
1) cluttering up the global namespace
2) making people three years down the line wonder why there's a function defined globally that's only used inside one other function

It keeps things organized. Notice how the function itself has no name, it's simply defined and assigned as a reference to $replacement.

But remember, you have to wait for PHP 5.3 :)

Solution 2 - Php

When you will need a function in the future which performs a task that you have decided upon now.

For example, if you read a config file and one of the parameters tells you that the hash_method for your algorithm is multiply rather than square, you can create a closure that will be used wherever you need to hash something.

The closure can be created in (for example) config_parser(); it creates a function called do_hash_method() using variables local to config_parser() (from the config file). Whenever do_hash_method() is called, it has access to variables in the local scope ofconfig_parser() even though it's not being called in that scope.

A hopefully good hypothetical example:

function config_parser()
{
	// Do some code here
	// $hash_method is in config_parser() local scope
	$hash_method = 'multiply';
	
	if ($hashing_enabled)
	{
		function do_hash_method($var)
	 	{
			// $hash_method is from the parent's local scope
			if ($hash_method == 'multiply')
				return $var * $var;
			else
				return $var ^ $var;
		}
	}
}


function hashme($val)
{
	// do_hash_method still knows about $hash_method
	// even though it's not in the local scope anymore
	$val = do_hash_method($val)
}

Solution 3 - Php

Apart from the technical details, closures are a fundamental pre-requisite for a programming style known as function oriented programming. A closure is roughly used for the same thing as you use an object for in object oriented programming; It binds data (variables) together with some code (a function), that you can then pass around to somewhere else. As such, they impact on the way that you write programs or - if you don't change the way you write your programs - they don't have any impact at all.

In the context of PHP, they are a little odd, since PHP already is heavy on the class based, object oriented paradigm, as well as the older procedural one. Usually, languages that have closures, has full lexical scope. To maintain backwards compatibility, PHP is not going to get this, so that means that closures are going to be a little different here, than in other languages. I think we have yet to see exactly how they will be used.

Solution 4 - Php

I like the context provided by troelskn's post. When I want to do something like Dan Udey's example in PHP, i use the OO Strategy Pattern. In my opinion, this is much better than introducing a new global function whose behavior is determined at runtime.

http://en.wikipedia.org/wiki/Strategy_pattern

You can also call functions and methods using a variable holding the method name in PHP, which is great. so another take on Dan's example would be something like this:

class ConfigurableEncoder{
        private $algorithm = 'multiply';  //default is multiply

        public function encode($x){
                return call_user_func(array($this,$this->algorithm),$x);
        }

        public function multiply($x){
                return $x * 5;
        }

        public function add($x){
                return $x + 5;
        }
        
        public function setAlgorithm($algName){
                switch(strtolower($algName)){
                        case 'add':
                                $this->algorithm = 'add';
                                break;
                        case 'multiply':        //fall through
                        default:                //default is multiply
                                $this->algorithm = 'multiply';
                                break;
                }
        }
}

$raw = 5;
$encoder = new ConfigurableEncoder();                           // set to multiply
echo "raw: $raw\n";                                             // 5
echo "multiply: " . $encoder->encode($raw) . "\n";              // 25
$encoder->setAlgorithm('add');
echo "add: " . $encoder->encode($raw) . "\n";                   // 10

of course, if you want it to be available everywhere, you could just make everything static...

Solution 5 - Php

A closure is basically a function for which you write the definition in one context but run in another context. Javascript helped me a lot with understanding these, because they are used in JavaScript all over the place.

In PHP, they are less effective than in JavaScript, due to differences in the scope and accessibility of "global" (or "external") variables from within functions. Yet, starting with PHP 5.4, closures can access the $this object when run inside an object, this makes them a lot more effective.

This is what closures are about, and it should be enough to understand what is written above.

This means that it should be possible to write a function definition somewhere, and use the $this variable inside the function definition, then assign the function definition to a variable (others have given examples of the syntax), then pass this variable to an object and call it in the object context, the function can then access and manipulate the object through $this as if it was just another one of it's methods, when in fact it's not defined in the class definition of that object, but somewhere else.

If it's not very clear, then don't worry, it will become clear once you start using them.

Solution 6 - Php

Bascially,Closure are the inner functions tat have access to the outer variables and are used as a callback function to anonmyous function (functions that do not have any name).

 <?php
      $param='ironman';
      function sayhello(){
          $param='captain';
          $func=function () use ($param){
                $param='spiderman';
          };
       $func();
       echo  $param;
       }
      sayhello();
?>

//output captain

//and if we pass variable as a reference as(&$param) then output would be spider man;

Solution 7 - Php

Closures:

MDN has the best explanation IMO:

> A closure is the combination of a function bundled together (enclosed) > with references to its surrounding state (the lexical environment). In > other words, a closure gives you access to an outer function’s scope > from an inner function.

i.e. A closure is a function with access to the variables which are in the parent scope. A closure allows us to conveniently create functions on the fly since in some situations a functions is only needed in one place (callbacks, callable arguments).

Example:

$arr = [1,2,3,3];
$outersScopeNr = 2;

// The second arg in array_filter is a closure
// It would be inconvenient to have this function in global namespace
// The use keyword lets us access a variable in an outer scope
$newArr = array_filter($arr, function ($el) use ($outersScopeNr) {
    return $el === 3 || $el === $outersScopeNr;
});

var_dump($newArr);
// array (size=3)
//  1 => int 2
//  2 => int 3
//  3 => int 3

Solution 8 - Php

Here are examples for closures in php

// Author: [email protected]
// Publish on: 2017-08-28

class users
{
	private $users = null;
	private $i = 5;
	
	function __construct(){
		// Get users from database
		$this->users = array('a', 'b', 'c', 'd', 'e', 'f');
	}
	
	function displayUsers($callback){
		for($n=0; $n<=$this->i; $n++){
			echo  $callback($this->users[$n], $n);
		}
	}
	
	function showUsers($callback){
		return $callback($this->users);
		
	}
	
	function getUserByID($id, $callback){
		$user = isset($this->users[$id]) ? $this->users[$id] : null;
		return $callback($user);
	}

}

$u = new users();

$u->displayUsers(function($username, $userID){
	echo "$userID -> $username<br>";
});

$u->showUsers(function($users){
	foreach($users as $user){
		echo strtoupper($user).' ';
	}
	
});

$x = $u->getUserByID(2, function($user){
	
	return "<h1>$user</h1>";
});

echo ($x);

Output:

0 -> a
1 -> b
2 -> c
3 -> d
4 -> e
5 -> f

A B C D E F 

c

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionrg88View Question on Stackoverflow
Solution 1 - PhpdirtsideView Answer on Stackoverflow
Solution 2 - PhpDan UdeyView Answer on Stackoverflow
Solution 3 - PhptroelsknView Answer on Stackoverflow
Solution 4 - PhpgrossvogelView Answer on Stackoverflow
Solution 5 - PhpRolfView Answer on Stackoverflow
Solution 6 - PhpHarsh GehlotView Answer on Stackoverflow
Solution 7 - PhpWillem van der VeenView Answer on Stackoverflow
Solution 8 - PhpHisham DalalView Answer on Stackoverflow