Aceptar función como parámetro en PHP

104

Me he estado preguntando si es posible o no pasar una función como parámetro en PHP; Quiero algo como cuando estás programando en JS:

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

Lo que quiero es ejecutar esa función en algún lugar de exampleMethod. ¿Es eso posible en PHP?

Cristian
fuente

Respuestas:

150

Es posible si está utilizando PHP 5.3.0 o superior.

Consulte Funciones anónimas en el manual.

En su caso, definiría exampleMethodasí:

function exampleMethod($anonFunc) {
    //execute anonymous function
    $anonFunc();
}
zombat
fuente
9
Maldita sea, sabía que era posible. Iba a responder, pero quería encontrar documentación para enlazar primero, y no sabía cómo se llamaba exactamente. Ah, bueno, ahora también sabré cuándo necesito hacer esto. Gracias.
Rob
3
Antes de 5.3 puedes usarcreate_function
Gordon
Muchas gracias. Como tengo que hacerlo para PHP4.3, supongo que tendré que hacer lo que quiera usando otra lógica.
Cristian
1
@Casidiablo: vea la respuesta de Jage, es posible que pueda hacer algo con create_function(). No es exactamente lo mismo, ya que tienes que pasar tu función como una cadena de código, que luego se pone eval()detrás de escena. No es ideal, pero es posible que pueda usarlo.
zombat
1
¿Cómo lo llamarías? ¿Podría dar un nombre de función existente? Por ejemplo:exampleMethod(strpos);
sumid
51

Solo para agregar a los demás, puede pasar un nombre de función:

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

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

callFunc('someFunc');

Esto funcionará en PHP4.

webbiedave
fuente
17

También puede usar create_function para crear una función como una variable y pasarla. Sin embargo, me gusta más la sensación de funciones anónimas . Vuélvete zombat.

Jage
fuente
+1 para la alternativa. Parece que el OP podría necesitarlo.
zombat
¡Gracias! Tengo que seguir con una instalación antigua de PHP 5.2 y las funciones de anonimato no funcionan allí.
diosney
Advertencia: esta función ha sido DEPRECADA a partir de PHP 7.2.0. No se recomienda confiar en esta función.
shamaseen
15

Solo codifícalo así:

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

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

Sería genial si pudieras inventar algo como esto (inspirado en Laravel Illuminate):

Object::method("param_1", function($param){
  $param->something();
});
Noche santa
fuente
exactamente lo que estaba buscando
Harvey
5

VERSIÓN PHP> = 5.3.0

Ejemplo 1: básico

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

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

Ejemplo 2: objeto std

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

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

Ejemplo 3: llamada de clase no estática

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

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

Ejemplo 4: llamada de clase estática

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

obj::test("param", function($param) {
    echo $param;
});
Pescante Gabrielyan
fuente
5

De acuerdo con la respuesta de @zombat, es mejor validar primero las funciones anónimas:

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

O valide el tipo de argumento desde PHP 5.4.0:

function exampleMethod(callable $anonFunc) {}
Nick Tsai
fuente
3

Probado para PHP 5.3

Como veo aquí, la función anónima podría ayudarlo: http://php.net/manual/en/functions.anonymous.php

Lo que probablemente necesitará y no se dijo antes es cómo pasar una función sin envolverla dentro de una función creada sobre la marcha . Como verá más adelante, deberá pasar el nombre de la función escrito en una cadena como parámetro, verificar su "capacidad de llamada" y luego llamarlo.

La función para verificar:

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

Luego, para llamarlo, use este fragmento de código (si también necesita parámetros, colóquelos en una matriz), que se ve en: http://php.net/manual/en/function.call-user-func.php

call_user_func_array( "string_holding_the_name_of_your_function", $arrayOfParameters );

como sigue (de una manera similar, sin parámetros):

    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");

Aquí hay una clase que explica cómo hacer algo 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);
        }
    }
}
?>

y un ejemplo de uso

<?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)*/
?>
Marco Ottina
fuente
2

Ejemplo simple usando una clase:

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;


});
Softmixt
fuente