Callback em PHP

Artigo que descreve o que é um callback e como ele é usado na linguagem PHP, através de exemplos práticos.

Introdução

Callback é um mecanismo utilizado por uma linguagem para que uma função seja transmitida na forma de parâmetro para outra função. Uma função com comportamento genérico recebe um callback por parâmetro e usa a função callback para realizar as operações específicas. Desta forma, é possível utilizar a função de diferentes formas.

O exemplo mais clássico é o de ordenação de arrays. Para ordenar um array numérico, normalmente usa-se a função sort. Esta função traz embutido dentro dela a estratégia utilizada para se comparar dois valores numéricos ou strings. Basicamente a estratégia é utilizar o operador "<" ou ">" para determinar qual valor é maior ou menor que o outro e aplicar sobre o algoritmo de ordenação.

Porém, a função sort não serve para ordenar um array de objetos, já que o operador "<" ou ">" não funcionaria adequadamente para se comparar dois objetos. Neste caso, é possível implementar uma função que compara dois objetos e passá-la para a função usort. Esta função serve para ordenar um array utilizando um algoritmo informado na forma de callback por parâmetro.

Vejamos um exemplo:

$array = array();

// Criando um array de 100 objetos cujo atributo "valor" e' aleatorio
for ($i = 0; $i < 100; $i++) {
    $obj = new stdClass();
    $obj->valor = rand(0, 1000);
    $array[] = $obj;
}

// Criando uma função que sabe comparar dois objetos
function comparar_objetos($obj1, $obj2) {
    if ($obj1->valor < $obj2->valor) {
        return -1;
    } elseif ($obj1->valor > $obj2->valor) {
        return +1;
    }
    return 0;
}

// Criando um callback
$callback = 'comparar_objetos';

// Usar usort com o callback
usort($array, $callback);

Representação de um Callback

As formas mais comuns de se representar um callback são:

  • Função: o callback é uma string que guarda o nome da função;
  • Método Não Estático: o callback é um array cuja posição zero guarda um objeto e a posição um guarda uma string com o nome do método não estático;
  • Método Estático: o callback pode ser uma string que guarda o nome da classe seguido de "::" e seguido do nome do método. Ou pode ser um array cuja posição zero guarda uma string com o nome da classe e a posição um guarda uma string com o nome do método estático. Ou pode ser representado de forma semelhante à representação do método não estático: através de um array com um objeto e o nome de um método estático;

Observações: no PHP 5.3, com o suporte a namespaces, o callback de funções ou métodos estáticos pode precisar do caminho absoluto do namespace onde a função ou a classe foram definidos.

Tanto funções do PHP quanto do usuário podem ser usadas para se montar um callback. Porém, lembre-se que existem elementos da linguagem que se parecem com funções, mas não são. Elas são chamadas "construções da linguagem". Alguns exemplos são: "echo", "isset", "unset", "list", "eval", "include", entre outros. Você deve olhar para uma construção da linguagem e vê-la como se fosse um "if", "while", "foreach", ou semelhante. São elementos da linguagem PHP e NÃO são funções.

Criando uma função genérica

Toda função/método que recebe um parâmetro do pseudo-tipo callback precisa especificar o que o callback recebe por parâmetro e o que ele deve retornar. Isso é importante para que o usuário que utilizar a função/método genérico possa implementar uma função de callback válida. No caso de um algoritmo de ordenação, a função deve receber dois parâmetros de qualquer tipo. Caso o primeiro seja considerado "menor" que o segundo, deve ser retornado um valor negativo. Caso o segundo seja considerado "menor" que o primeiro, deve ser retornado um valor positivo. E caso os elementos sejam considerados "iguais", deve ser retornado o valor zero.

Você é capaz de criar sua própria função que recebe um callback por parâmetro. Para usá-lo, basta chamar a função call_user_func_array ou call_user_func. Outra alternativa é chamar a "função com nome variável". Uma função útil para verificar se o parâmetro informado é um callback válido é a função "is_callable". Normalmente é utilizado este recurso em funções que manipulam arrays ou coleções.

Exemplo de função genérica para obter o menor elemento do array:

/**
 * Retorna o menor elemento do array de acordo com uma funcao callback
 * @param array $array Array de qualquer tipo
 * @param callback $callback Funcao que compara dois elementos do array
 * @return mixed O menor valor encontrado
 */
function menor(array $array, $callback) {

    // Checar parametro
    if (!is_callable($callback)) {
        trigger_error('Invalid callback parameter', E_USER_ERROR);
        return false;
    }

    // Obtendo o menor valor
    list($pos, $menor) = each($array);
    while (list($pos, $elemento) = each($array)) {

        // Usando o callback para comparar o elemento corrente com o menor encontrado
        $comparacao = call_user_func($callback, $elemento, $menor);

        // Se o elemento corrente e' menor que o menor encontrado, ele passa a ser o menor
        if ($comparacao < 0) {
            $menor = $elemento;
        }
    }
    return $menor;
}

2 comentários

Flavio disse...

Incrível, mesmo sendo um artigo de 2010, é um dos poucos artigos sobre assunto.
Parabéns pela didática Rubens