Ce qui en termes simples est une fonction récursive utilisant PHP

est-ce que quelqu'un peut m'expliquer une fonction récursive en PHP (sans utiliser Fibonacci) en langage layman et en utilisant des exemples? je regardais un exemple, mais le Fibonacci totalement perdu moi!

Merci d'avance ;-) En outre, combien de fois les utilisez-vous dans le développement web?

67
demandé sur James Westgate 2010-04-16 01:05:31

16 réponses

Laymens termes:

une fonction récursive est une fonction qui appelle elle-même

un peu plus en profondeur:

si la fonction continue de s'appeler, comment sait-elle quand s'arrêter? Vous définissez une condition connue comme une base de cas. Les cas de Base indiquent à notre appel récursif quand s'arrêter, sinon il va boucler à l'infini.

ce qui était un bon exemple d'apprentissage pour moi, puisque j'ai un forte expérience en mathématiques, était factoriel . Par les commentaires ci-dessous, il semble que la fonction factorielle peut être un peu trop, je vais le laisser ici, juste au cas où vous vouliez.

function fact($n) {
  if ($n === 0) { // our base case
     return 1;
  }
  else {
     return $n * fact($n-1); // <--calling itself.
  }
}

en ce qui concerne l'utilisation de fonctions récursives dans le développement web, Je n'ai pas personnellement recours à l'utilisation d'appels récursifs. Non pas que je considère comme une mauvaise pratique de compter sur la récursion, mais ils ne devraient pas être votre première option. Ils ont peut être mortel s'il n'est pas utilisé correctement.

bien que je ne puisse pas rivaliser avec l'exemple du répertoire, j'espère que cela aidera quelque peu.

(4/20/10) mise à jour:

il serait également utile de vérifier cette question, où la réponse acceptée démontre en termes profanes comment une fonction récursive fonctionne. Même si la question de L'OP portait sur Java, le concept est le même,

84
répondu Anthony Forloney 2017-05-23 11:33:24

un exemple serait d'imprimer chaque fichier dans n'importe quel sous-répertoire d'un répertoire donné (si vous n'avez pas de liens symboliques à l'intérieur de ces répertoires qui peuvent briser la fonction d'une façon ou d'une autre). Un pseudo-code d'impression de tous les fichiers ressemble à ceci:

function printAllFiles($dir) {
    foreach (getAllDirectories($dir) as $f) {
        printAllFiles($f); // here is the recursive call
    }
    foreach (getAllFiles($dir) as $f) {
        echo $f;
    }
}

L'idée est d'imprimer tous les sous répertoires en premier et ensuite les fichiers du répertoire courant. Cette idée appliquée à tous les sous-répertoires, et c'est la raison de l'appel de cette fonction de manière récursive pour tous les sous annuaire.

si vous voulez essayer cet exemple , vous devez vérifier les répertoires spéciaux . et .. , sinon vous êtes coincé à appeler printAllFiles(".") tout le temps. En outre, vous devez vérifier ce qu'il faut imprimer et ce qu'est votre répertoire de travail actuel (Voir opendir() , getcwd() , ...).

30
répondu Progman 2013-11-18 14:16:52

la récursion est quelque chose qui se répète. Comme une fonction qui s'appelle de l'intérieur. Permettez-moi de démontrer dans un exemple un peu pseudo:

Imagine que tu es avec tes potes buvant de la bière, mais ta femme va te donner un enfer si tu ne rentres pas avant minuit. Pour ce faire, créons la fonction orderAndDrinkBeer($time) où $time est minuit moins le temps qu'il vous faut pour finir votre boisson actuelle et rentrer à la maison.

donc, en arrivant au bar, vous commandez votre première bière et commencez à boire:

$timeToGoHome = '23';  // Let's give ourselves an hour for last call and getting home

function orderAndDrinkBeer($timeToGoHome) {  // Let's create the function that's going to call itself.
    $beer = New Beer();  // Let's grab ourselves a new beer
    $currentTime = date('G'); // Current hour in 24-hour format

    while ($beer->status != 'empty') {  // Time to commence the drinking loop
        $beer->drink();  // Take a sip or two of the beer(or chug if that's your preference)
    }

    // Now we're out of the drinking loop and ready for a new beer

    if ($currentTime < $timeToGoHome) { // BUT only if we got the time
        orderAndDrinkBeer($timeToGoHome);  // So we make the function call itself again!
    } else {  // Aw, snap!  It is time :S
        break; // Let's go home :(
    }
}

espérons maintenant que vous n'avez pas pu boire assez de bière pour devenir si intoxiqué que votre femme va vous faire dormir sur le canapé indépendamment d'être à la maison à l'heure -.-

Mais oui, c'est à peu près comme la récursion.

21
répondu Freyr 2010-10-27 10:59:35

C'est une fonction qui s'appelle elle-même. Il est utile pour la marche de certaines structures de données qui se répètent, comme les arbres. Un DOM HTML en est un exemple classique.

un exemple de structure de l'arbre en javascript et une fonction récursive pour "marcher" l'arbre.

    1
   / \
  2   3
     / \
    4   5

--

var tree = {
  id: 1,
  left: {
    id: 2,
    left: null,
    right: null
  },
  right: {
    id: 3,
    left: {
      id: 4,
      left: null,
      right: null
    },
    right: {
      id: 5,
      left: null,
      right: null
    }
  }
};

pour marcher dans l'arbre, nous appelons la même fonction à plusieurs reprises, en passant les noeuds enfants du noeud courant à la même fonction. Nous puis d'appeler la fonction, d'abord sur le nœud de gauche, puis sur la droite.

dans cet exemple, nous obtiendrons la profondeur maximale de l'arbre

var depth = 0;

function walkTree(node, i) {

  //Increment our depth counter and check
  i++;
  if (i > depth) depth = i;

  //call this function again for each of the branch nodes (recursion!)
  if (node.left != null) walkTree(node.left, i);
  if (node.right != null) walkTree(node.right, i);

  //Decrement our depth counter before going back up the call stack
  i--;
}

enfin nous appelons la fonction

alert('Tree depth:' + walkTree(tree, 0));

une grande façon de comprendre la récursion est de parcourir le code à l'exécution.

9
répondu James Westgate 2010-04-15 22:15:09

simplement dit: une fonction récursive est une fonction qui s'appelle elle-même.

7
répondu Samuel 2013-11-18 14:17:15

c'est très simple, quand une fonction appelle elle-même pour accomplir une tâche pour un nombre indéterminé et fini de temps. Un exemple de mon propre code, fonction pour peupler un avec arbre de catégorie à plusieurs niveaux

function category_tree($parent=0,$sep='')
{
    $q="select id,name from categorye where parent_id=".$parent;
    $rs=mysql_query($q);
    while($rd=mysql_fetch_object($rs))
    {
        echo('id.'">'.$sep.$rd->name.'');
        category_tree($rd->id,$sep.'--');
    }
}
5
répondu Imran Naqvi 2010-10-27 12:44:20

la récursion est une façon fantaisiste de dire "Faites encore cette chose jusqu'à ce qu'elle soit faite".

deux choses importantes à avoir:

  1. un scénario de base - vous avez un but à atteindre.
  2. un test-Comment savoir si vous devez savoir où vous allez.

Imaginez une tâche simple: Trier une pile de livres par ordre alphabétique. Un processus simple serait de prendre les deux premiers livres, de les trier. Maintenant, voici l' partie récursive: y a-t-il d'autres livres? Si oui, le faire à nouveau. Le "do it again" est la récursion. Le" y a-t-il d'autres livres " est le test. Et "non, plus de livres" est le cas de base.

4
répondu Shane Castle 2010-04-15 21:48:00

meilleure explication que j'ai trouvé quand j'ai appris que moi-même est ici: http://www.elated.com/articles/php-recursive-functions/

C'est parce qu'une chose:

la fonction lorsque son appelé est créé en mémoire (nouvelle instance est créée)

ainsi la fonction récursive ne S'appelle pas elle-même , mais son appel autre exemple - si ce n'est pas une fonction dans la mémoire de faire de la magie. Son couple d'instances en mémoire qui se renvoient des valeurs - et ce comportement est le même lorsque, par exemple, la fonction a appelle la fonction B. Vous avez deux instances aussi bien que si la fonction récursive s'appelle la nouvelle instance d'elle-même.

essayez de dessiner la mémoire avec des instances sur le papier - cela aura du sens.

2
répondu Ales 2017-04-14 05:17:49

la récursion est une alternative aux boucles, il est assez rare qu'elles apportent plus de clarté ou d'élégance à votre code. Un bon exemple a été donné par la réponse de Progman, s'il n'utilisait pas la récursion, il serait forcé de garder la trace dans laquelle il est actuellement (ceci est appelé état) les récursions lui permet de faire la comptabilité en utilisant la pile (la zone où les variables et l'adresse de retour d'une méthode sont stockées)

les exemples standard factoriel et Fibonacci sont pas utile pour comprendre le concept car ils sont faciles à remplacer par une boucle.

1
répondu stacker 2010-04-15 21:46:11

essentiellement ceci. Il continue de s'appeler jusqu'à son fait

void print_folder(string root)
{
    Console.WriteLine(root);
    foreach(var folder in Directory.GetDirectories(root))
    {
        print_folder(folder);
    }
}

fonctionne aussi avec des boucles!

void pretend_loop(int c)
{
    if(c==0) return;
    print "hi";
    pretend_loop(c-);
}

vous pouvez également essayer de googler. Notez le "vouliez-vous dire" (cliquez sur elle...). http://www.google.com/search?q=recursion&spell=1

1
répondu Alex 2015-08-14 09:56:52

voici un exemple pratique (il y en a déjà plusieurs bons). Je voulais juste en ajouter un qui est utile à presque tous les développeurs.

à un moment donné, les développeurs devront analyser un objet comme une réponse d'une API ou d'un type d'objet ou d'un tableau.

cette fonction est initialement appelée pour analyser un objet qui peut ne contenir que des paramètres, mais que se passe-t-il si l'objet contient aussi d'autres objets ou tableaux? Ce devra être adressée, et pour la plupart la fonction de base le fait déjà, de sorte que la fonction appelle simplement lui-même à nouveau (après avoir confirmé que la clé ou la valeur est soit un objet ou un tableau) et parse ce nouvel objet ou tableau. En fin de compte, ce qui est retourné est une chaîne qui crée chaque paramètre sur une ligne par elle-même pour la lisibilité, mais vous pouvez tout aussi facilement enregistrer les valeurs dans un fichier journal ou insérer dans un DB ou autre.

j'ai ajouté le paramètre $prefix pour utiliser le parent élément pour aider à décrire la variable finale afin que nous puissions voir ce que la valeur se rapporte. Il n'inclut pas des choses comme les valeurs nulles, mais cela peut être modifié à partir de cet exemple.

si vous avez l'objet:

$apiReturn = new stdClass();
$apiReturn->shippingInfo = new stdClass();
$apiReturn->shippingInfo->fName = "Bill";
$apiReturn->shippingInfo->lName = "Test";
$apiReturn->shippingInfo->address1 = "22 S. Deleware St.";
$apiReturn->shippingInfo->city = "Chandler";
$apiReturn->shippingInfo->state = "AZ";
$apiReturn->shippingInfo->zip = 85225;
$apiReturn->phone = "602-312-4455";
$apiReturn->transactionDetails = array(
    "totalAmt" => "100.00",
     "currency" => "USD",
     "tax" => "5.00",
     "shipping" => "5.00"
);
$apiReturn->item = new stdClass();
$apiReturn->item->name = "T-shirt";
$apiReturn->item->color = "blue";
$apiReturn->item->itemQty = 1;

et utilisation:

var_dump($apiReturn);

il sera de retour:

object(stdClass)#1 (4) { ["shippingInfo"]=> object(stdClass)#2 (6) { ["fName"]=> string(4) "projet de Loi" ["lName"]=> string(4) "Test" ["adresse1"]=> string(18) "22 S. Deleware Saint" ["ville"]=> string(8) "Chandler" ["etat"]=> string(2) "AZ" ["zip"]=> int(85225) } ["téléphone"]=> string(12) "602-312-4455" ["transactionDetails"]=> array(4) { ["totalAmt"]=> string(6) "100.00" ["euro"]=> string(3) "USD" ["impôt"]=> string(4) "5.00" ["envoi"]=> string(4) "5.00" } ["rubrique"]=> object(stdClass)#3 (3) { ["name"]=> string(7) "T-shirt" ["couleur"]=> string(4) "bleu" ["itemQty"]=> int(1) } }

et voici le code pour le diviser en une chaîne avec un saut de ligne pour chaque paramètre:

function parseObj($obj, $prefix = ''){
    $stringRtrn = '';
    foreach($obj as $key=>$value){
        if($prefix){
            switch ($key) {
                case is_array($key):
                    foreach($key as $k=>$v){
                        $stringRtrn .= parseObj($key, $obj);
                    }
                    break;
                case is_object($key):
                    $stringRtrn .= parseObj($key, $obj);
                    break;
                default:
                    switch ($value) {
                        case is_array($value):
                            $stringRtrn .= parseObj($value, $key);
                            break;
                        case is_object($value):
                            $stringRtrn .= parseObj($value, $key);
                            break;
                        default:
                            $stringRtrn .= $prefix ."_". $key ." = ". $value ."<br>";
                            break;
                    }
                    break;
            }
        } else { // end if($prefix)
            switch($key){
                case is_array($key):
                    $stringRtrn .= parseObj($key, $obj);
                    break;
                case is_object($key):

                    $stringRtrn .= parseObj($key, $obj);
                    break;
                default:
                    switch ($value) {
                        case is_array($value):
                            $stringRtrn .= parseObj($value, $key);
                            break;
                        case is_object($value):
                            $stringRtrn .= parseObj($value, $key);
                            break;                      
                        default:
                            $stringRtrn .= $key ." = ". $value ."<br>";
                            break;
                    } // end inner switch 
            } // end outer switch
        } // end else
    } // end foreach($obj as $key=>$value)
    return $stringRtrn;
} // END parseObj()

ceci retournera l'objet comme suit:

shippingInfo_fName = Bill
shippingInfo_lName = Test
shippingInfo_address1 = 22 S. Deleware St.
shippingInfo_city = Chandler
shippingInfo_state = AZ
shippingInfo_zip = 85225
phone = 602-312-4455
transactionDetails_totalAmt = 100.00
transactionDetails_currency = USD
transactionDetails_tax = 5.00
transactionDetails_shipping = 5.00
item_name = T-shirt
item_color = blue
item_itemQty = 1

j'ai fait le interrupteur emboîté déclarations pour éviter la confusion avec if . . . ifelse . . . else , mais il était presque aussi long. Si ça peut aider, demandez juste les conditionnels if et je peux les coller pour ceux qui en ont besoin.

1
répondu Joel 2017-01-15 20:40:28

marcher à travers un arbre répertoire est un bon exemple. Vous pouvez faire quelque chose de similaire pour traiter un tableau. Voici une fonction récursive très simple qui traite simplement une chaîne, Un tableau simple de chaînes, ou un tableau imbriqué de chaînes de n'importe quelle profondeur, remplaçant les instances de 'hello' par 'goodbye' dans la chaîne ou les valeurs du tableau ou n'importe quel sous-tableau:

function replaceHello($a) {
    if (! is_array($a)) {
        $a = str_replace('hello', 'goodbye', $a);
    } else {
        foreach($a as $key => $value) {
            $a[$key] = replaceHello($value);
        }
    }
    return $a
}

Il sait quand s'arrêter parce qu'à un certain point, la "chose", il est en cours de traitement n'est pas une tableau. Par exemple, si vous appelez replaceHello('hello'), il reviendra 'au revoir'. Si vous lui envoyez un tableau de chaînes, bien qu'il s'appellera lui-même une fois pour chaque membre du tableau, alors retournez le tableau traité.

0
répondu Bob Ray 2014-07-04 22:16:16

si vous ajoutez une certaine valeur (dites, "1") à L'exemple D'Anthony Forloney, tout serait clair:

function fact(1) {
  if (1 === 0) { // our base case
  return 1;
  }
  else {
  return 1 * fact(1-1); // <--calling itself.
  }
}

origine:

function fact($n) {
  if ($n === 0) { // our base case
    return 1;
  }
  else {
  return $n * fact($n-1); // <--calling itself.
  }
}
0
répondu Kevin 2014-07-21 06:49:29

c'est un exemple très simple de factoriel avec récursion:

Factorials sont un concept de mathématiques très facile. Ils sont écrits comme 5! et cela signifie 5 * 4 * 3 * 2 * 1. So 6! 720 et 4! 24 ans.

function factorial($number) { 

    if ($number < 2) { 
        return 1; 
    } else { 
        return ($number * factorial($number-1)); 
    } 
}

j'espère que cela vous sera utile. :)

0
répondu 2015-09-15 07:49:11

- Il un exemple simple récursive (Y)

<?php 


function factorial($y,$x) { 

    if ($y < $x) { 
        echo $y; 
    } else { 
        echo $x; 
        factorial($y,$x+1);
    } 
}

$y=10;

$x=0;
factorial($y,$x);

 ?>
0
répondu Ignacio Olivieri 2017-01-07 12:51:06

récursion utilisée pour la constante de Kaprekar

function KaprekarsConstant($num, $count = 1) {
    $input = str_split($num);
    sort($input);

    $ascendingInput  = implode($input);
    $descendingInput = implode(array_reverse($input));

    $result = $ascendingInput > $descendingInput 
        ? $ascendingInput - $descendingInput 
        : $descendingInput - $ascendingInput;

    if ($result != 6174) {
        return KaprekarsConstant(sprintf('%04d', $result), $count + 1);
    }

    return $count;

}

la fonction continue de s'appeler avec le résultat du calcul jusqu'à ce qu'elle atteigne la constante de Kaprekars, à laquelle elle retournera le nombre de fois où les calculs ont été faits.

/éditer pour toute personne qui ne connaît pas la constante de Kaprekars, il a besoin d'une entrée de 4 chiffres avec au moins deux chiffres distincts.

0
répondu Bart 2018-03-02 07:34:31