PHP 5.3 parte 3: Lambda e Closures
Closures
O recurso de Lambda não adiciona nenhuma funcionalidade em especial em relação a versão 4, onde podemo reproduzir o uso de funções anônimas através da função create_function. É ai que entra em cena, no php 5.3, o recurso chamado Closures. Closures funcionam como Lambdas, porém de forma mais inteligente. Permitem a interação com variáveis fora do ambiente de onde são definidos.
Veja abaixo um exemplo bem simples da utilização de Closures:
A saída do código anterior:
Variáveis de fora do ambiente do closure podem ser importadas através da palavra-chave use. No exemplo anterior a variável $string foi importada para dentro do closure. Por padrão as variáveis importadas são passadas por valor e não por referência. Dessa forma se quisermos que a variável importada seja modificada dentro do closure, e que a mudança continue aplicada após a chamada da função, devemos utilizar o operador & para especificar que a variável esta sendo passada por referência e não por valor.
Segue abaixo mais um exemplo da utilização de closures importando variáveis por referência:
A saída do script anterior:
O recurso de Lambda não adiciona nenhuma funcionalidade em especial em relação a versão 4, onde podemo reproduzir o uso de funções anônimas através da função create_function. É ai que entra em cena, no php 5.3, o recurso chamado Closures. Closures funcionam como Lambdas, porém de forma mais inteligente. Permitem a interação com variáveis fora do ambiente de onde são definidos.
Veja abaixo um exemplo bem simples da utilização de Closures:
<?php $string = "Olá teste!"; $closure = function() use ($string) { echo $string; }; $closure();
A saída do código anterior:
Olá teste!
Variáveis de fora do ambiente do closure podem ser importadas através da palavra-chave use. No exemplo anterior a variável $string foi importada para dentro do closure. Por padrão as variáveis importadas são passadas por valor e não por referência. Dessa forma se quisermos que a variável importada seja modificada dentro do closure, e que a mudança continue aplicada após a chamada da função, devemos utilizar o operador & para especificar que a variável esta sendo passada por referência e não por valor.
Segue abaixo mais um exemplo da utilização de closures importando variáveis por referência:
<?php $a = 10; $closure = function() use (&$a) { $a += 50; }; $closure(); var_dump ($a); $closure(); var_dump ($a); $closure(); var_dump ($a);
A saída do script anterior:
int(60) int(110) int(160)
Aliás, o __invoke só é chamado quando a instância é invocada com os parênteses né? Acho que o primeiro exemplo do "$validacao = validacao()" nem funcionaria...
05/01/2010 9:40pm
(~15 anos atrás)
Estive pensando: será que seria uma boa usar o __invoke para retornar a instância de uma classe singleton?
Algo assim:
Ficaria apenas assim:
Não sei se isso tornaria o código menos intuitivo, já que "getInstance" é consagrado.
Mas se formos parar pra pensar: sempre que se usar o __invoke perderemos um pouco da legibilidade, afinal, estaremos omitindo o nome de um método. Afinal, onde este método seria útil?
Quem sabe para métodos que retornam objetos...
Enfim, as vezes o PHP tras umas coisas que nos faz pensar nas novas possibilidades...
Algo assim:
$validacao = validacao::getInstance();
Ficaria apenas assim:
$validacao = validacao();
Não sei se isso tornaria o código menos intuitivo, já que "getInstance" é consagrado.
Mas se formos parar pra pensar: sempre que se usar o __invoke perderemos um pouco da legibilidade, afinal, estaremos omitindo o nome de um método. Afinal, onde este método seria útil?
Quem sabe para métodos que retornam objetos...
// Obtendo um usuario $usuario = $alguma_coisa->usuario; // Obtendo um usuario com codigo 1 $usuario = $alguma_coisa->usuario(3);
Enfim, as vezes o PHP tras umas coisas que nos faz pensar nas novas possibilidades...
05/01/2010 9:35pm
(~15 anos atrás)
O método __invoke pode ser usado para que uma classe se comporte como um closure. Imagino que a principal utilidade do closure seria em funções que aceitam callback como parâmetro. Funções como array_map, usort, etc.
Vamos supor que você queira criar diversas funções de comparação para utilizar em uma rotina de ordenação, como usort. Você pode criar diversas classes implementando o método __invoke e passar as instâncias dessas classes como parâmetro para a função usort.
Veja o exemplo abaixo para entender melhor:
Criamos uma classe testeInvoke implementando o método mágico __invoke e passamos a sua instância para a função usort ordernar o array.
O resultado do script anterior: