Aceite a função como parâmetro em PHP

104

Tenho me perguntado se é possível ou não passar uma função como parâmetro em PHP; Eu quero algo como quando você está programando em JS:

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

O que eu quero é executar essa função em algum lugar em exampleMethod. Isso é possível em PHP?

Cristian
fonte

Respostas:

150

É possível se você estiver usando o PHP 5.3.0 ou superior.

Consulte Funções anônimas no manual.

No seu caso, você definiria exampleMethodassim:

function exampleMethod($anonFunc) {
    //execute anonymous function
    $anonFunc();
}
zumbat
fonte
9
Droga, eu sabia que era possível. Ia responder, mas queria encontrar alguma documentação para vincular primeiro e não sabia como era chamado exatamente. Bem, agora vou saber quando precisar fazer isso também. Obrigado.
Rob
3
Antes do 5.3 você pode usarcreate_function
Gordon
Muito obrigado. Já que tenho que fazer isso para PHP4.3, acho que terei que fazer o que quero usando outra lógica.
Cristian
1
@Casidiablo - Veja a resposta de Jage, você pode fazer algo com create_function(). Não é exatamente a mesma coisa, já que você tem que passar sua função como uma string de código, que então é eval()exibida nos bastidores. Não é o ideal, mas você pode usá-lo.
zombat
1
Como você chamaria? Você poderia dar um nome para a função existente? Por exemplo:exampleMethod(strpos);
verão de
51

Só para adicionar aos outros, você pode passar um nome de função:

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

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

callFunc('someFunc');

Isso funcionará no PHP4.

webbiedave
fonte
17

Você também pode usar create_function para criar uma função como uma variável e distribuí -la. Porém, eu gosto mais da sensação de funções anônimas . Go zombat.

Jage
fonte
1 para a alternativa. Parece que o OP pode precisar disso.
zombat
Obrigado! Eu tenho que ficar com uma instalação antiga do PHP 5.2 e funções anonymoys não funcionam lá.
diosney
Aviso: Esta função foi DESCONTINUADA a partir do PHP 7.2.0. Depender desta função é altamente desencorajado.
shamaseen
15

Basta codificar assim:

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

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

seria ótimo se você pudesse inventar algo assim (inspirado no Laravel Illuminate):

Object::method("param_1", function($param){
  $param->something();
});
Saint Night
fonte
exatamente o que eu estava procurando
Harvey,
5

PHP VERSION> = 5.3.0

Exemplo 1: básico

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

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

Exemplo 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;
});

Exemplo 3: chamada de classe não 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;
});

Exemplo 4: chamada de classe estática

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

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

De acordo com a resposta de @ zombat, é melhor validar as Funções Anônimas primeiro:

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

Ou valide o tipo de argumento desde o PHP 5.4.0:

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

Testado para PHP 5.3

Como vejo aqui, a função anônima pode ajudá-lo: http://php.net/manual/en/functions.anonymous.php

Provavelmente, o que você precisará e não foi dito antes é como passar uma função sem envolvê-la em uma função criada instantaneamente . Como você verá mais tarde, você precisará passar o nome da função escrito em uma string como um parâmetro, verificar sua "capacidade de chamada" e chamá-la.

A função para fazer a verificação:

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

Então, para chamá-lo, use este pedaço de código (se você também precisar de parâmetros, coloque-os em um array), visto em: http://php.net/manual/en/function.call-user-func.php

call_user_func_array( "string_holding_the_name_of_your_function", $arrayOfParameters );

da seguinte forma (de forma semelhante, sem 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");

Aqui está uma aula que explica como fazer algo semelhante:

<?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);
        }
    }
}
?>

e um exemplo 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
fonte
2

Exemplo simples usando uma classe:

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
fonte