Você está profundos do pescoço em 3 anos de idade código de produção, amazon um clique check-out não está funcionando, e sua esposa acabou de deixar você por alguém que "não gastar tanto tempo a escrever testes de unidade." Você precisa salvar o mundo através da implementação de um algoritmo usando uma função anônima agora .
Espere, o que se o problema que precisamos resolver é bem servida com uma abordagem recursiva? Talvez você atacar o problema de forma otimista, começando com algo como isto:
<? Php
$ Fibonacci = função ( $ n ) {
retorno ( $ n < 2 ) ? $ n : ( $ fibonacci ( $ n - 1 ) + fibonacci $ ( $ n - 2 ) );
};
echo $ fibonacci ( 4 ); / / deve ser (0,1,2,3,4) -> (0,1,1,2,3)
ver-prima super-ingênuo-approach.php Gist Este trazido a você por GitHub .
"Bem, uma porcaria", você diz, vendo o erro fatal relatado pelo PHP . Acontece que as variáveis chamadas como funções deve ser uma instância de Encerramento , uma instância de uma classe que implementa __invoke () , ou uma string representando uma função chamada no namespace global. No corpo da função anônima acima, $ fibonacci é nenhum desses. É uma variável, não declarado livre no fechamento criado pela função anônima. No momento em que ele é chamado, ele não foi vinculado, por isso o aviso de que você teria obtido se o relatório de erro foram fixadas a um limiar bastante alto e, portanto, não pode ser chamado como nada , muito menos como uma função.
Então, como você deve proceder? A solução clássica seria simplesmente para nomear esta função, em vez de se ligar a função a uma variável chamada $ fibonacci , devemos apenas o nome da função fibonacci . Que certamente seria conveniente. Mas o que se encontramos uma função de ordem superior que espera uma função como um parâmetro? Acontece que muitas funções de ordem superior em PHP pode simplesmente aceitar como callbacks os nomes de funções, mas eu prefiro não contar com isso. De fato, qualquer função userland você escreve que espera um lambda vai funcionar tão feliz sendo enviada uma string. Mas o que se deve fornecer a função de ordem superior com os meios de cálculo do enésimo número de Fibonacci? Como poderíamos mesmo ir sobre como implementar a recursão obrigados a retirá-lo? Estou tão feliz que você pediu.
Nomear o inominável
A parte difícil sobre o acima é que nós não temos nenhuma boa maneira de realmente chamar a função em cujo corpo, estamos executando enquanto ainda estamos nele. A coisa é anônimo, afinal de contas, somos essencialmente à procura de alguma maneira de quebrar seu anonimato, para chamar o nameless pelo nome. Bem, podemos não ser capazes de realmente extrair o nome desta função com o propósito de chamá-lo de novo, mas temos algumas informações sobre o local onde é realizada em memória. Este local é conhecido por $ fibonacci , o valor que estamos usando no escopo pai para manter a própria função. Portanto, se nós poderíamos pegar o valor de $ fibonacci , poderíamos usá-lo para recurse. O problema aqui é que $ fibonacci não existe no âmbito onde precisamos usá-lo.
Se você tivesse lido meu artigo sobre o fechamento , você sabe que nós temos a habilidade em PHP para fazer algo que parece muito com isso. Com PHP é usar palavras-chave para definição de função anônima, podemos puxar um valor ou uma referência para o escopo de uma função. Vamos ser ingênuos e puxar o valor de $ fibonacci em uma tentativa equivocada de forshadowingly recurse:
<? Php
$ Fibonacci = função ( $ n ) uso ( $ fibonacci ) {
retorno ( $ n < 2 ) ? $ n : ( $ fibonacci ( $ n - 1 ) + fibonacci $ ( $ n - 2 ) );
};
echo $ fibonacci ( 4 ); / / Erro Fatal: Nome da função deve ser uma string
ver-prima ingênuo-fechamento approach.php- Este Gist trazido a você por GitHub .
Esta nova função tem realmente o corpo exatamente como a nossa tentativa original; a única diferença é que agora estamos puxando no valor de $ fibonacci do escopo pai e vinculando-a definição de tempo. A execução deste, nós realmente obter o erro exato a mesma que temos acima. Por quê?
Sem entrar nos pequenos pormenores, vamos andar com o que está acontecendo aqui. Em primeiro lugar, nós declaramos uma variável chamada $ fibonacci e depois atribuir a ele a função anônima. Aqui está o problema: esta declaração função não termina até que , após o valor de $ fibonacci é puxado para dentro de seu corpo e usados. Uma vez que estamos use @ @ ing $ fibonacci por valor, esse valor é declarado, mas indefinido quando nós realmente puxá-lo para o escopo da função. Note que não há erro fatal aqui , até que realmente executar $ fibonacci () . Isso é muito importante.
Fechamento por referência
Vendo que isso não funciona, vamos dar uma abordagem um pouco diferente, trazendo $ fibonacci na função anônima por referência (na linguagem funcional, vamos fechar nossos função anônima sobre $ fibonacci ). Ao fazer isso, nós ainda puxe $ fibonacci em nossa função antes que ela realmente se refere a qualquer coisa útil. No entanto, porque estamos fechando por referência, e não por valor, $ fibonacci será devidamente definida no momento em que realmente precisa para executá-lo. Lembre-se como nós não conseguimos o erro, o valor executado até que a função? Que o problema vai embora agora, porque no momento em que executar a função, a variável de segurá-lo para nós é realmente segurá-lo para nós.
<? Php
$ Fibonacci = função ( $ n ) uso ( & $ fibonacci ) {
retorno ( $ n < 2 ) ? $ n : ( $ fibonacci ( $ n - 1 ) + fibonacci $ ( $ n - 2 ) );
};
echo $ fibonacci ( 4 ); / / Mostra "2"
ver-prima fechamento por reference.php- Este Gist trazido a você por GitHub .
Agora que temos uma função recursiva que trabalham anônima, vamos explorar alguns exemplos do que podemos fazer com ele. Uma coisa legal sobre esta aplicação particular (que certamente não é devido à sua natureza anônima, mas sim por projeto) é que é completamente não-destrutiva.
Aplicações
Aqui estão algumas aplicações do que temos feito acima:
mapa :
Programação funcional em PHP é um "todo nother nível de feio. Aqui está uma implementação do mapa , uma função de ordem superior que tem uma função de argumento simples e aplica-o a cada elemento em uma coleção. Aqui, nós passá-lo $ fibonacci , que detém a nossa função recursiva anônimos.
<? Php
função map ( $ f , matriz $ seq , conjunto mapeado $ = matriz () ) {
se ( ! vazia ( $ seq ) ) $ mapeados [] = $ f ( redefinir ( $ seq ) );
retorno ! vazia ( $ seq ) ? mapa ( $ f , array_slice ( $ seq , 1 ), mapeados $ ) : $ mapeadas ;
}
print_r ( mapa ( $ fibonacci , faixa ( 1 , 5 ) ) ); / / Mapas inteiros para Fibs
ver-prima map.php Este Gist trazido a você por GitHub .
reduzir :
reduzir é outra função de ordem superior comum. É preciso uma função de dois argumentos e uma coleção e mapas a matriz de pares em um único valor usando a função.
<? Php
função de reduzir ( $ f , matriz $ seq , $ s = 0 ) {
$ S = ! vazia ( $ seq ) ? $ f ( $ s , redefinir ( $ seq ) ) : $ s ;
retorno ! vazia ( $ seq ) ? reduzir ( $ f , array_slice ( $ seq , 1 ), $ s ) : $ s ;
}
echo reduzir ( função ( $ a , $ b ) { retorno $ a + $ b ; }, mapa ( $ fibonacci , faixa ( 1 , 5 ) ), 0 ); / / Mostra 12
ver-prima reduce.php Este Gist trazido a você por GitHub .
Conclusão
Se estivéssemos em uma situação onde precisávamos fazer uso de uma função de ordem superior, como um desses acima, seria muito inconveniente para ser limitado a apenas usando funções anônimas que não poderia ser escrito de forma recursiva. Com estes "passar por referência fechamentos" em PHP , podemos contornar essa limitação e fornecer aos nossos função anônima para qualquer função de ordem superior que pode usá-lo.
Esta ainda é uma solução um pouco pobre, no entanto, porque as nossas funções não são mais verdadeiramente anónimos. Em vez de ligar o nome da função a um identificador, estamos vinculando o nome da nossa função para uma variável. No caso de nós queria mudar o nome da função, ou proporcionar a recursividade como este em uma função interna anônima, poderíamos luta.
Nenhum comentário :
Postar um comentário