247 votes

Fonctions PHP récursives anonymes

Est-il possible d'avoir une fonction PHP à la fois récursive et anonyme? Ceci est ma tentative pour le faire fonctionner, mais il ne passe pas dans le nom de la fonction.

 $factorial = function( $n ) use ( $factorial ) {
    if( $n <= 1 ) return 1;
    return $factorial( $n - 1 ) * $n;
};
print $factorial( 5 );
 

Je suis également conscient que c'est une mauvaise façon de mettre en œuvre le factoriel, c'est juste un exemple.

461voto

Zurahn Points 4682

Pour que cela fonctionne, vous devez passer $ factorial comme référence

 $factorial = function( $n ) use ( &$factorial ) {
    if( $n == 1 ) return 1;
    return $factorial( $n - 1 ) * $n;
};
print $factorial( 5 );
 

27voto

Kendall Hopkins Points 12193

Je sais que ce ne serait pas une approche simple, mais j'ai appris une technique appelée "fix" de langages fonctionnels. L' fix fonction de Haskell est connu plus généralement sous forme de Y combinator, qui est l'un des plus connus de point fixe combinators.

Un point fixe est une valeur qui est inchangé par une fonction: d'un point fixe d'une fonction f est tout x tel que x = f(x). Un combinateur de point fixe o est une fonction qui retourne un point fixe pour toute fonction f. Étant donné que y(f) est un point fixe de f, nous avons y(f) = f(y(f)).

Essentiellement, le Y combinator crée une nouvelle fonction qui prend en compte tous les arguments de l'original, plus un argument supplémentaire qui est la fonction récursive. Comment cela fonctionne est le plus évident à l'aide de la notation. Au lieu d'écrire des arguments entre parenthèses (f(x,y,...)), les écrire après la fonction: f x y .... Le Y combinator est défini comme Y f = f (Y f); ou, avec un seul argument pour la recursed fonction, Y f x = f (Y f) x.

Depuis PHP n'est pas automatiquement curry fonctions, c'est un peu un hack pour faire fix de travail, mais je pense que c'est intéressant.

function fix( $func )
{
    return function() use ( $func )
    {
        $args = func_get_args();
        array_unshift( $args, fix($func) );
        return call_user_func_array( $func, $args );
    };
}

$factorial = function( $func, $n ) {
    if ( $n == 1 ) return 1;
    return $func( $n - 1 ) * $n;
};
$factorial = fix( $factorial );

print $factorial( 5 );

Remarque c'est presque la même que la simple fermeture des solutions publiés par d'autres, mais la fonction fix crée la fermeture pour vous. Point fixe combinators sont légèrement plus complexe que l'utilisation d'une fermeture, mais sont plus générales, et avoir d'autres usages. Alors que la méthode de fermeture est plus approprié pour PHP (ce qui n'est pas vraiment un langage fonctionnel), le problème d'origine est un exercice que pour la production, et donc le Y combinator est une approche viable.

-4voto

St. John Johnson Points 4163

Essayez ceci (utilise global):

  $factorial = function($n) {
   global $factorial;
   if ($n == 1) return 1;
   return $factorial($n - 1) * $n;
 };
 

ou (en utilisant create_function et nowdoc)

  $factorial = create_function('$n', <<<'EOL'
   global $factorial; 
   if( $n == 1 ) return 1;
   return $factorial($n - 1) * $n;
   EOL
 );
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X