Accept function as parameter in PHP

I've been wondering whether it is possible or not to pass a function as a parameter in PHP. I want something similar to when you're programming the following code in JavaScript:

object.exampleMethod(function(){
// some stuff to execute
});

What I want is to execute that function somewhere in exampleMethod. Is that possible in PHP?

131709 次浏览

It's possible if you are using PHP 5.3.0 or higher.

See Anonymous Functions in the manual.

In your case, you would define exampleMethod like this:

function exampleMethod($anonFunc) {
//execute anonymous function
$anonFunc();
}

Valid: (PHP 4 >= 4.0.1, PHP 5, PHP 7)

You can also use create_function to create a function as a variable and pass it around. Though, I like the feeling of anonymous functions better. Go zombat.


Update 09 - Jan - 2022

Warning

This function has been DEPRECATED as of PHP 7.2.0, and REMOVED as of PHP 8.0.0. Relying on this function is highly discouraged.

Just to add to the others, you can pass a function name:

function someFunc($a)
{
echo $a;
}


function callFunc($name)
{
$name('funky!');
}


callFunc('someFunc');

This will work in PHP4.

Just code it like this:

function example($anon) {
$anon();
}


example(function(){
// some codes here
});

it would be great if you could invent something like this (inspired by Laravel Illuminate):

Object::method("param_1", function($param){
$param->something();
});

Simple example using a class :

class test {


public function works($other_parameter, $function_as_parameter)
{


return $function_as_parameter($other_parameter) ;


}


}


$obj = new test() ;


echo $obj->works('working well',function($other_parameter){




return $other_parameter;




});

PHP VERSION >= 5.3.0

Example 1: basic

function test($test_param, $my_function) {
return $my_function($test_param);
}


test("param", function($param) {
echo $param;
}); //will echo "param"

Example 2: std object

$obj = new stdClass();
$obj->test = function ($test_param, $my_function) {
return $my_function($test_param);
};


$test = $obj->test;
$test("param", function($param) {
echo $param;
});

Example 3: non static class call

class obj{
public function test($test_param, $my_function) {
return $my_function($test_param);
}
}


$obj = new obj();
$obj->test("param", function($param) {
echo $param;
});

Example 4: static class call

class obj {
public static function test($test_param, $my_function) {
return $my_function($test_param);
}
}


obj::test("param", function($param) {
echo $param;
});

Tested for PHP 5.3

As i see here, Anonymous Function could help you: http://php.net/manual/en/functions.anonymous.php

What you'll probably need and it's not said before it's how to pass a function without wrapping it inside a on-the-fly-created function. As you'll see later, you'll need to pass the function's name written in a string as a parameter, check its "callability" and then call it.

The function to do check:

if( is_callable( $string_function_name ) ){
/*perform the call*/
}

Then, to call it, use this piece of code (if you need parameters also, put them on an array), seen at : http://php.net/manual/en/function.call-user-func.php

call_user_func_array( "string_holding_the_name_of_your_function", $arrayOfParameters );

as it follows (in a similar, parameterless, way):

    function funToBeCalled(){
print("----------------------i'm here");
}
function wrapCaller($fun){
if( is_callable($fun)){
print("called");
call_user_func($fun);
}else{
print($fun." not called");
}
}


wrapCaller("funToBeCalled");
wrapCaller("cannot call me");

Here's a class explaining how to do something similar :

<?php
class HolderValuesOrFunctionsAsString{
private $functions = array();
private $vars = array();


function __set($name,$data){
if(is_callable($data))
$this->functions[$name] = $data;
else
$this->vars[$name] = $data;
}


function __get($name){
$t = $this->vars[$name];
if(isset($t))
return $t;
else{
$t = $this->$functions[$name];
if( isset($t))
return $t;
}
}


function __call($method,$args=null){
$fun = $this->functions[$method];
if(isset($fun)){
call_user_func_array($fun,$args);
} else {
// error out
print("ERROR: Funciton not found: ". $method);
}
}
}
?>

and an example of usage

<?php
/*create a sample function*/
function sayHello($some = "all"){
?>
<br>hello to <?=$some?><br>
<?php
}


$obj = new HolderValuesOrFunctionsAsString;


/*do the assignement*/
$obj->justPrintSomething = 'sayHello'; /*note that the given
"sayHello" it's a string ! */


/*now call it*/
$obj->justPrintSomething(); /*will print: "hello to all" and
a break-line, for html purpose*/


/*if the string assigned is not denoting a defined method
, it's treat as a simple value*/
$obj->justPrintSomething = 'thisFunctionJustNotExistsLOL';


echo $obj->justPrintSomething; /*what do you expect to print?
just that string*/
/*N.B.: "justPrintSomething" is treated as a variable now!
as the __set 's override specify"*/


/*after the assignement, the what is the function's destiny assigned before ? It still works, because it's held on a different array*/
$obj->justPrintSomething("Jack Sparrow");




/*You can use that "variable", ie "justPrintSomething", in both ways !! so you can call "justPrintSomething" passing itself as a parameter*/


$obj->justPrintSomething( $obj->justPrintSomething );
/*prints: "hello to thisFunctionJustNotExistsLOL" and a break-line*/


/*in fact, "justPrintSomething" it's a name used to identify both
a value (into the dictionary of values) or a function-name
(into the dictionary of functions)*/
?>

According to @zombat's answer, it's better to validate the Anonymous Functions first:

function exampleMethod($anonFunc) {
//execute anonymous function
if (is_callable($anonFunc)) {
$anonFunc();
}
}

Or validate argument type since PHP 5.4.0:

function exampleMethod(callable $anonFunc) {}

Here is a simple procedural example of how you could implement validation of multiple data items using separate functions for each data item validation, passed as an array of functions argument to a master validations function, with the data to be validated (the arguments to the functions) passes as the other array argument to the master validation function. Useful for writing generic code to validate form data.

<?php
function valX($value) {
echo "<p>Validating $value == 5</p>";
if ($value == 5) {
return true;
} else {
return false;
}
}


function valY($value) {
echo "<p>Validating $value == 6</p>";
if ($value == 6) {
return true;
} else {
return false;
}
}


function validate($values, $functions) {
for ($i = 0; $i < count($values); $i++) {
if ($functions[$i]($values[$i])) {
echo "<p>$values[$i] passes validation</p>";
} else {
echo "<p>$values[$i] fails validation</p>";
}
}
}


$values = [5, 9];
$functions = ['valX', 'valY'];
validate($values, $functions);
?>