PHP 5.3 parte III: Lambda e Closures

Posted on dezembro 19, 2009. Filed under: PHP |

Nesta terceira parte de nossa série vamos abordar a utilização de Lambda e Closures que também foram recursos incluídos na versão 5.3. Funções “Lambdas” são conhecidas como funções anônimas. Closures são uma forma mais avançada de “Lambdas” permitindo trabalhar com funções anônimas de forma mais flexível e com menos limitações. Vamos entender agora o funcionamento desses dois novos rescursos.

Lambdas

“Lambdas” são conhecidas como funções anônimas. Estas funções podem ser definidas em qualquer lugar, podendo ser atribuídas à uma variável. A função existe somente no escopo de onde a variável foi definida. Caso a variável saia fora do escopo, a função também se torna indisponível.

É mais comum o uso de “Lambdas” em lugares que aceitam funções callback como parâmetro. Um exemplo é a função array_map. Segue a abaixo um exemplo usando função anônima com array_map:

<?php
$r = array_map(function($value) {
               return $value * 4;
              }, array(2, 4, 6, 8, 10));

print_r ($r);

A saída do script anterior será:
8
16
24
32
40

Perceba que usamos apenas 1 parâmetro na função anônima, $value. O número de parâmetros varia de acordo com o número de arrays passados para a função array_map.

Poderíamos ter utilizado a função create_function, disponível desde a versão 4 do php, para criar funções anônimas. Porém tem algumas desvantagens. Uma delas é que ela é compilada em tempo de execução (runtime) ao invés de ser em tempo de compilação (compile time). Isto impacta no desempenho do script, além de ser uma syntax desagradável.

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”:

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

Veja que o valor da variável $a é modificada após a chamada do closure.

Método __invoke

Foi adicionado no php5.3 um método mágico chamado __invoke, utilizado em classes, que permite que o objeto seja chamado como se fosse uma função, ou closure. Segue o exemplo:

<?php
class DebugAll {
   public function __invoke($var) {
     var_dump($var);
   }
}

$obj1 = new DebugAll;
$obj1(50);
$obj1(100);

A saída do script anterior será:
int(50)
int(100)

Exemplos úteis de utilização de Closures

Closures são bastante úteis em funções que utilizam callbacks. Outra forma de tirar proveito de closures é refactorar velhos códigos afim de deixá-los mais limpos. Veja o exemplo abaixo, onde usamos o método Logger::log para logar uma observação para cada query executada no banco de dados:

<?php
$db = mysqli_connect("server","user","pass");
Logger::log('debug','database','Conectando com a base de dados');

$db->query('insert into users (nome, descricao) values ('Douglas','Administrador');
Logger::log('debug','database','Insert Douglas into to users table');

$db->query('insert into users (nome, descricao) values ('Andréia','Redatora');
Logger::log('debug','database','Insert Andreia into to users table');

Refactorando o código acima para utilizar closures deixamos o código mais agradável para ler e entender.
Segue abaixo o código refactorado:
<?php
// definindo o closure
$logdb = function ($string) { Logger::log('debug','database',$string); };

$db = mysqli_connect("server","user","pass");
$logdb('Conectando com a base de dados');
$db->query('insert into users (nome, descricao) values ('Douglas','Administrador');
$logdb('Insert Douglas into to users table');
$db->query('insert into users (nome, descricao) values ('Andréia','Redatora');
$logdb('Insert Andreia into to users table');

Make a Comment

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google

Você está comentando utilizando sua conta Google. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s

Liked it here?
Why not try sites on the blogroll...

%d blogueiros gostam disto: