My Profile Photo

Jociel Souza

PHP Clojure Javascript Mongodb ZendFramework


Desenvolvedor Web - Backend - PHP


Estudante de Ciência da Computação, desenvolvedor de software apaixonado por tecnologia.


Estudante de Ciência da Computação procurando sempre aprender algo novo, desenvolvedor web com conhecimento em PHP7^, Zend Framework, Zend Expressive, Doctrine ORM, Doctrine ODM, MongoDB, Javascript, VueJS, HTML, GIT entre outros, atualmente estudando também Clojure, Elm e o paradigma funcional e tentando compartilhar o conhecimento adquirido.


PHP-Lambda functions, Closures, Partials Functions, Currying | Jociel Souza

PHP-Lambda functions, Closures, Partials Functions, Currying



Lambda functions, closures, partials functions, curryng, são conceitos e técnicas existentes há muito tempo na área de ciência da computação, principalmente no estudo do paradigma de desenvolvimento funcional. Muitos destes conceitos vem sendo adotado por linguagens a priori orientada a objetos, no PHP não é diferente, já a algum tempo podemos implementar várias destas técnicas.

Nate Grant em Unsplash


Desde a versão 5.3 o PHP tem suporte a lambda functions e também tem suporte a First-Class Functions e High-Order Functions. First-Class Functions permite tratar uma função como qualquer outro valor, atribuí-la a uma variável, passá-la como parâmetro, etc. High-Order Functions significa que uma função pode receber outra função como argumento e/ou retornar uma função como resultado. Algumas funções desse tipo que já existem no core do PHP e que são bastante utilizadas são por exemplo: array_map, array_reduce, funções de ordenação: usort, uksort.


Isso nos permite implementar algumas técnicas de programação funcional e criar códigos mais expressivos, fáceis de ler e dar manutenção. Também possibilita uma maior reutilização de códigos, agilizando o desenvolvimento e deixando o projeto mais consistente. Vamos ver como funciona e como podemos implementar essas técnicas.



Lambda functions/Funções anônimas

Funções anônimas simplesmente permite a criação de uma função sem nome específico, podendo ser atribuída a uma variável, passada como argumento para uma função ou como retorno de uma função.

No primeiro exemplo criamos uma função anônima que recebe dois parâmetros e atribuímos a variável $sum, assim chamamos como uma função normalmente. No segundo exemplo criamos uma função nomeada soma que recebe um callback(função) como primeiro parâmetro e mais dois números como parâmetros, ao chamar essa função passamos como callback a função anônima $sum, dentro dessa função executamos o callback passando os dois números restantes.



Closures

Uma Closure é semelhante a uma função anônima, a diferença esta no fato de que uma Closure tem acesso a variáveis do escopo externo. Para isso o PHP possui a palavra-chave use, possibilitando passar qualquer variável do escopo externo para dentro da função.

No primeiro exemplo criamos uma função anônima comum tentando acessar uma variável do escopo externo, ao tentar executar a função temos um “PHP Notice” dizendo que a variável $name dentro da função não existe. Na segunda função usamos o use para passar a varável $name para dentro da função, assim temos acesso a ela ao chamarmos a função.


Lambda functions/Closures são instancia da classe Closure, esta classe possui alguns métodos.

Closure::call

Vincula a Closure temporariamente a um objeto/escopo e a chama com qualquer parâmetro passado.

Na linha 21 e 22 estamos chamando a Closure $addAge vinculando ao escopo do objeto $person1 e $person2 respectivamente, e passando o parâmetro que ela necessita, então ela esta executando como se fosse um método interno aos respectivos objetos.

Closure::bindTo/Closure::bind

Os métodos bindTo/bind retorna uma nova Closure com um objeto e um escopo vinculado, não é temporário, assim, se o objeto vinculado for alterado, o resultado da chamada da nova Closure poderá ter seu valor alterado também. Clojure::bind é uma versão static de Closure::bindTo.

Nesse exemplo estamos usando os métodos bindTo e bind(static) para vincular definitivo a Closure $addAge nos objetos $person1 e $person2 respectivamente. Esse método retorna uma nova Closure que estamos atribuindo a $closurePerson1 e $closurePerson2. Aqui podemos perceber que se alterarmos a propriedade $age dos objetos e chamarmos $closurePerson1 e $closurePerson2 novamente o resultado retornado é diferente.

Closure::fromCallable

Closure::fromCallable permite converter um Callable(função) em uma Closure. Para isso precisamos passar a função que queremos converter como parâmetro para esse método. Essa função verifica se o callable esta no escopo atual, se for do escopo externo vai lançar um erro.



Partial functions

Utilizando Closures podemos criar algo chamando partials functions. Partials functions são funções que pegam uma função existente e reduzem a quantidade de parâmetros ligando um ou mais de seus parâmetros a um valor específico, retornando uma outra função com esses parâmetros já definidos. As partials functions permite dividir em funções mais específicas e compartilhar a funcionalidade central de uma função mais ampla. O objetivo é poder fixar os argumentos necessários e retornar outra função com esses valores definidos, e assim, na chamada da nova função, definir apenas os parâmetros restantes.

No exemplo acima, praticamente criamos um “constrututor” de funções de multiplicação. Criamos uma função makeMultiply que recebe um número como parâmetro ($x) e retorna uma outra função, mas já fixando um valor da multiplicação como o parâmetro recebido, assim podemos construir outras funções mais específicas utilizando esta como base. Por exemplo, se quisermos uma função que multiplica qualquer número por 2 (linha 11) ou por 5 (linha 12), podemos usa-la para isso.


Podemos criar uma função generalista que retorna uma partial function de qualquer outra função, assim podemos reutilizá-la sempre que necessário.


Assim, possibilita criarmos funções generalista e ir criando as funções mais específicas quando necessário, o mesmo exemplo de cima.



Currying

Utilizando Closures também podemos fazer currying de funções. Currying é uma técnica utilizada para transformar uma função que recebe múltiplos parâmetros em uma cadeia de funções, cada uma lidando com apenas um parâmetro da função inicial. Após feito o currying, uma função rebe o primeiro parâmetro e devolve uma função que aceita o segundo e assim por diante.

No primeiro exemplo utilizando uma função comum recebendo três parâmetros, e retornando a soma dos mesmos. No segundo código, utilizando currying, separamos a lógica em três funções, cada uma trabalhando com apenas um parâmetro, assim podemos chamá-la como uma sequência de funções. Embora se pareça com partials function, currying e partials functions são conceitos e técnicas diferentes.



Conclusão

Acabamos de ver algumas técnicas utilizando lambda functions/Closure que auxiliam na resolução de problemas, reusabilidade de código e construção de um código mais limpo e expressivo.

Cada caso deve ser avaliado e estudado qual a melhor técnica para resolver determinado problema, os recursos estão disponíveis, bastando apenas a aplicação da resolução.

Referências:
https://wiki.php.net/rfc/closurefromcallable

https://wiki.php.net/rfc/closure_apply

Livro PHP 7 Data Structures and Algorithms

Livro Pro Functional PHP Programming

comments powered by Disqus