quakenet:#php Tutorial

Author: Progman, zuletzt bearbeitet von progman @ 2005/02/18 13:14:46

Bitte beachten Sie, dass die Tutorialkapitel zusammenhängen. Wenn sie direkt auf ein Kapitel verlinkt wurden müssen Sie gegebenenfalls die vorherigen Kapitel auch lesen. Achten Sie beim lesen darauf, dass Sie kein Kapitel überspringen.

Rekursion

  1. Was ist Rekursion?
  2. Fakultät von der Zahl x
  3. Ausgabe eines Verschachtelten Arrays
  4. Foren mit Baumstruktur
  5. Verzeichnis mit Unterverzeichnissen ausgeben
  6. Fibonacci-Zahlen
  7. Taschenrechner
  8. Fazit

1. Was ist Rekursion?

Früher oder später werdet ihr auf ein Problem stoßen, dass man nur rekursiv lösen kann. Das hat jetzt nix mit der Textschreibart Kursiv zu tun. Rekursives Programmieren bzw. Rekursive Funktionsaufrufe braucht ihr, wenn ihr z.B. etwas verschachteltes ausgeben oder errechnen wollt. Dazu werde ich hier einige Beispiele erläutern, wo man dieses Rekursive braucht.

In der Programmierwelt heißt Rekursion, dass eine Funktion sich selber aufruft. Dies könnte z.B. so aussehen.

<?php
    
function foobar()
    {
       echo
"Ich stürzte ab<br />";flush();
       
foobar();
    }
?>

Natürlich ist eure Frage berechtigt: Warum soll man so ein scheiss machen? Wenn man jetzt diese Funktion aufruft, haben wir eine Endlos-Schleife. Wir haben zwar keine richtige Schleife wie while und for, doch PHP wird bei diesem Code abschmieren. Denn die Funktion wird ja nie verlassen. Im Gegenteil, sie wird immer neu aufgerufen. Dies macht PHP so oft, bis z.B. die 30 Sekunden Time-Evaltion abgelaufen sind, oder der Speicher voll ist. Also, wenn man nicht bei Rekursionen aufpasst kann man richtig scheisse machen.

Rekursive Funktionen ruft man üblicherweise auch mit einem Parameter auf. In der Funktion wird dann auf diesen Parameter zugegriffen und es werden entsprechende Funktionen und so ausgeführt. Innerhalb dieser Funktion ruf sich dann die Funktion selber auf, aber mit einem etwas anderen Parameter. Dann wird wieder die Funktion abgearbeitet. Dies geht dann immer so weiter. Damit PHP nun wieder nicht abschmiert muss man eine, ich nenne es mal, Abbruch-Bedingung schreiben. Bei dieser Bedingung ruft sich die Funktion nicht selber auf. Dies ist dann das Ende des Funktionsaufrufs. Nun kommen ein paar Beispiele wo man sowas braucht.

2. Fakultät von der Zahl x

Wenn ihr euch mal euren Taschenrechner anguckt, dann werdet ihr irgentwo, vielleicht auf einer 2nd.-Funktion, eine Taste sehen die so aussieht: x!. Diese Rechenart nennt man Fakultät. Man kann nur natürliche Zahlen (positive ganze Zahlen) für Fakultäten benutzen, wie 4 oder 11. Im Taschenrechner gibt man dann z.B. die Zahl 5 ein und drückt die x! Taste. Als Ergebnis bekommt man dann die Zahl 120. Nun was hat die Zahl 5 mit 120 gemeinsam. Ihr könnt ja mal andere Werte testen. Mit einfachen Taschenrechner könnt ihr maximal die Fakultät von 69 bilden, die bei 10^98 oder so liegt. Bei Fakultät von 70 streigt euer Rechner und es kommt ein Error oder E. Hier sind mal die Fakultäten der ersten 5 Zahlen.

0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
...
        

Doch wie erzeugt der Taschenrechner diesen Wert. Nach ein wenig ausprobieren werdet ihr vielleicht darauf kommen. Allgemein wurde definiert, dass die Fakultät von 0 das Ergebnis 1 hat.

Um euch nicht auf die Folter zu spannen: Die Fakultät einer Zahl ist das Produkt der ganzen Zahlen von 1 bis n. Die Fakultät von 5 ist also 1*2*3*4*5 und das ist 120. Die Fakultät von 3 ist 1*2*3 = 6.

0! = 1
1! = 1
2! = 1*2
3! = 1*2*3
4! = 1*2*3*4
5! = 1*2*3*4*5
...
        

Dies kann man sehr leicht mit einer For-Schleife lösen.

<?php
    $zahl
= 6;
    
$erg = 1;
    for (
$i=1; $i<=$zahl; $i++) {
        
$erg *= $i;
    }
    echo
$zahl.'! :'.$erg;
?>

Aber da ist nix Rekursives bei. Die Fakultät einer Zahl ist aber anders definiert.

n! = n * (n-1)!
        

Die Fakultät von 5 ist also 5 mal die Fakultät von 4. Für die Fakultät von 4 gilt das dann auch: 4 mal die Fakultät von 3. Dies geht so weit bis zur Fakultät 0 runter. Dies ist die End-Bedingung. Per Definition ist die Fakultät von 0 gleich 1.

0! = 1
n! = n * (n-1)!
        

Dies muss man machen, weil sonst der Wert zu weit runtergeht und dann mit 0 malgenommen wird. Und 0 mal x ist 0, das bringt uns nicht weiter. Wir definieren uns jetzt eine Funktion, die die Fakultät einer Zahl bestimmt. Wir definieren die Funktion so.

mixed fakul(int number)
        

Der Rückgabewert ist deshalb nicht int, weil der Wert sehr groß sein kann. Wenn er klein genug ist ist er vom Typ Integer, wenn nicht, vom Typ Float. Aber darüber brauchen wir uns eigentlich keine Gedanken machen.

Da die Funktion einen Wert zurückliefern soll, müssen wir mit return arbeiten. Zuerst wandeln wir den Parameter in eine Integer-Zahl um.

<?php
    
function fakul($zahl)
    {
        
$zahl = (int)$zahl;
    }
?>

Dann gucken wir, ob der Wert kleiner oder gleich 0 ist.

<?php
    
function fakul($zahl)
    {
        
$zahl = (int)$zahl;
        if (
$zahl <= 0) {
            
// ...
        
} else {
            
// ...
        
}
    }
?>

Wenn die Zahl kleiner gleich 0 ist, ist der Rückgabewert 1

<?php
    
function fakul($zahl)
    {
        
$zahl = (int)$zahl;
        if (
$zahl <= 0) {
            
$ret_value = 1;
        } else {
            
// ...
        
}
    }
?>

Wenn er nicht kleiner gleich 0 ist, errechnen wir die Fakultät laut der oben stehenden Funktion.

<?php
    
function fakul($zahl)
    {
        
$zahl = (int)$zahl;
        if (
$zahl <= 0) {
            
$ret_value = 1;
        } else {
            
$ret_value = $zahl /* mal die Fakultät von $zahl-1 */;
        }
    }
?>

Jetzt brauchen wir nur noch eine Funktion, die uns die Fakultät von einer Zahl errecht.... hey, so eine Funktion haben wir doch. Diese Funktion haben wir doch grade definiert, sie lautet fakul(). Dies nennt man nun Rekursion.

<?php
    
function fakul($zahl)
    {
        
$zahl = (int)$zahl;
        if (
$zahl <= 0) {
            
$ret_value = 1;
        } else {
            
$ret_value = $zahl * fakul($zahl-1);
        }
    }
?>

Damit die Funktion auch einen Wert zurückliefert, sollten wir auch ein return benutzen.

<?php
    
function fakul($zahl)
    {
        
$zahl = (int)$zahl;
        if (
$zahl <= 0) {
            
$ret_value = 1;
        } else {
            
$ret_value = $zahl * fakul($zahl-1);
        }
        return
$ret_value;
    }
?>

Man kann es natürlich auch direkt mit return 1; oder return $zahl * fakul($zahl-1); machen. Aber ich wollte es mal mit einer extra Variablen machen. So eine Funktion kann man nun beliebig aufrufen.

<?php
    
for ($i=0; $i <= 10; $i++) {
        echo
$i.'! = '.fakul($i)."<br />\n";
    }
?>

3. Ausgabe eines Verschachtelten Arrays

Es kann sein, das man verschachtelte Arrays in seinem Script habt. Wir schreiben nun eine Funktion, mit der wir das komplette Array ausgeben. Sowas wird auch rekursiv gelöst. Dabei gucken wir uns jedes Arrayelement an. Wenn dies kein Array ist, wird der Wert einfach ausgegeben. Wenn dies aber doch ein Array ist, so wird dieses Array mit dieser Funktion ausgegeben. Wir nennen diese Funktion mal echoarray.

<?php
    
function echoarray($var)
    {
        if(
is_array($var)) {
            echo
"<ul>\n";
            foreach(
$var as $value) {
                echo
"<li>\n";
                
echoarray($value);
                echo
"</li>\n";
            }
            echo
"</ul>\n";
        } else {
            echo
$var;
        }
    }
?>

Je nach dem, ob der Parameter ein Array ist oder nicht wird der Wert entweder direkt ausgegeben, oder es wird die Funktion mit den Arrayelementen aufgerufen. Wenn es ein Array ist, wird zur besseren Übersicht auch noch eine Unsortierte Liste mittels HTML erstellt.

So eine Funktion brauchen wir nicht neu zu schreiben. So eine Funktion haben wir schon. Sie heißt print_r. Das r kommt dabei von recursive.

4. Foren mit Baumstruktur

Im internet findet man zwei Arten von Foren. Die eine Gruppe nennt sich Board. Solche Boards sind wie folgt aufgebaut.

board
 |-forumgruppe
 |  |-forum
 |  |  |-thread
 |  |  |  |-reply
 |  |  |  |-reply
 |  |  |  `-reply
 |  |  `-thread
 |  |     `-reply
 |  |-forum
 |  |  |-thread
 |  |  `-thread
 |  |     |-reply
 |  |     `-reply
 |  `-forum
 |-forumgruppe
 |  |-forum
 |  |  |-thread
 |  |  | `-reply
 |  |  |-thread
 |  |  |  |-reply
 |  |  |  `-reply
 |  |  `-thread
 |  `-forum
 |     `-thread
 `-forumgruppe
    |-forum
    |  `-thread
    |     |-reply
    |     `-reply
    |-forum
    |  |-thread
    |  `-thread
    |     `-reply
    `-forum
        

Solche Foren sind sehr einfach zu Programmieren. Das liegt daran, dass das Tabellenlayout sehr einfach aufgebaut ist. Dies sieht etwa so aus.

board_gruppen(ID,Name)
board_forum(ID,GroupID,Name)
board_topic(ID,ForumID,Thema)
board_reply(ID,TopicID,Name,Email,Datum,Text)
        

Die entsprechenden Tabellen enthalten die ID-Schlüssel der anderen Tabellen. Somit kann man z.B. einen Topic eindeutig seinem Forum zuordnen. In dieser Schreibweise ist auch nix rekursives vorhanden. Um eine Forenübersicht zu erstellen braucht man 'nur' 2 verschachtelte MySQL-Querys. Ein Query ließt die Gruppen aus, der andere Query die dazugehörigen Foren (WHERE `GroupID` = '".$row['ID']."'). Passt auf das ihr euch dann die Result und/oder Fetch-Werte überschreibt. So ein Forum findet man auf www.counter-strike.de.

Die andere Gruppe Forum nennt man schon eher Forum. Sie sind so wie Newsgroups aufgebaut. Auf jedem Beitrag kann ein individueller Beitrag geschrieben werden. Die Beiträge sind somit an einem Beitrag, nicht an einem Topic gebunden, wie oben in einem board. Dies sieht dann etwa so aus.

Forum
 |-Beitrag
 |  `-Beitrag
 |     |-Beitrag
 |     |-Beitrag
 |     |  `-Beitrag
 |     `-Beitrag
 |-Beitrag
 |  |-Beitrag
 |  |-Beitrag
 |  `-Beitrag
 |-Beitrag
 |  `-Beitrag
 |     `-Beitrag
 |        `-Beitrag
 |           `-Beitrag
 |              |-Beitrag
 |              |  `-Beitrag
 |              `-Beitrag
 |-Beitrag
 |  |-Beitrag
 |  `-Beitrag
 |     `Beitrag
 |-Beitrag
 |-Beitrag
 |  `-Beitrag
 |-Beitrag
 `-Beitrag
     |-Beitrag
     `-Beitrag
        

Die Anzahl der Tiefen ist dabei egal. In einem Board gibt es eigentlich nur 4 Tiefen/Ebenen: Gruppe - Forum - Topic - Reply. Bei einem echten Forum gibt es keine Beschränkung für die Tiefe. Auf eine Antwort kann eine Antwort gegeben werden, und auf diese auch wieder eine Antwort, und auf diese auch, und auch auf diese. Dies sieht dann so aus. Beitrag - Beitrag - Beitrag - Beitrag - Beitrag usw. . Die Dazugehörige Datenbankstruktur sieht so aus.

Beitrag(ID,ParentID,Autor,Email,Text,Betreff,Datum)
        

Die ParentID gibt an, zu welchem vorherigen Beitrag diese Antwort gehört. Üblicherweise speichert man dort eine 0, wenn dieser Beitrag ein neuer Beitrag ist, der zu keinem anderen Beitrag gehört.

Um jetzt einen Thread und dessen Antworten auszugeben, benutzt man auch eine Rekursion. Diese ist so aufbebaut.

zeigeThread(x)
wenn dieser Thread antworten hat
    zeige von jeder Antwort den Thread an
wenn nicht
    zeige nur diese Antwort an.
        

Dies könnte dann so aussehen.

<?php
    
function zeigeThread($id = 0)
    {
        
$id = (int)$id;
        if(
$id) {
            
// Zeige speziellen Thread
            
$sql = "SELECT
                        ID,
                        Betreff,
                        Autor
                    FROM
                        beitrag
                    WHERE
                        ID = '"
.$id."';";
            
$thread = new Query($sql);
            if(
$thread->error()) {
                die(
"<pre>".$thread->getError()."</pre>\n");
            }
            if(
$row = $thread->fetch()) {
                echo
$row['Betreff']." (".$row['Autor'].")\n";
                
// nun dessen Antworten holen
                
$sql = "SELECT
                            ID
                        FROM
                            beitrag
                        WHERE
                            ParentID = '"
.$row['ID']."'
                        ORDER BY
                            Datum DESC;"
;
                
$replys = new Query($sql);
                if(
$replys->error()) {
                    die(
"<pre>".$replys->getError()."</pre>\n");
                }
                if(
$replys->numRows()) {
                    echo
"<ul>\n";
                    while(
$reply = $replys->fetch()) {
                        echo
"<li>\n";
                        
zeigeThread($reply['ID']);
                        echo
"</li>\n";
                    }
                    echo
"</ul>\n";
                } else {
                    
// brauche nix anzeigen. Auf diesem Beitrag
                    // wurde noch nicht geantwortet.
                
}
            } else {
                echo
"<p>\n";
                echo
"    Es gibt kein Thread mit dieser ID\n";
                echo
"</p>\n";
            }
        } else {
            
$sql = "SELECT
                        ID
                    FROM
                        beitrag
                    ORDER BY
                        Datum DESC;"
;
            
$replys = new Query($sql);
            if(
$replys->error()) {
                die(
"<pre>".$replys->getError()."</pre>\n");
            }
            if(
$replys->numRows()) {
                echo
"<ul>\n";
                while(
$reply = $replys->fetch()) {
                    echo
"<li>\n";
                    
zeigeThread($reply['ID']);
                    echo
"</li>\n";
                }
                echo
"</ul>\n";
            } else {
                echo
"<p>\n";
                echo
"    Keine Beiträge in diesem Forum vorhanden.\n";
                echo
"</p>\n";
            }
        }
    }
?>

Das Forum wird nun mit einem einzigen zeigeThread(); komplett angezeigt. Die Beiträge werden in einer sogenannten Baumstruktur angezeigt, was man auch im Windows-Explorer kennt. Dort kann man noch zusätzlich bestimmte Äste des Baumes (also Verzeichnisse) ausblenden.

Statt dem Parent-ID verfahren gibt es auch ein Nested Sets verfahren. Dort werden die Beiträge auch als Baumstruktur gespeichert, doch in einer etwas anderen Weise. Dieses Thema wird auch noch im Tutorial durchgenommen. Analog dazu kann man auch bei Google nach Nested Sets suchen.

5. Verzeichnis mit Unterverzeichnissen ausgeben

In PHP kann man nicht so ohne weiteres ein Verzeichnis mit Unterverzeichnissen ausgeben. Aber zumindest haben wir eine dir-Klasse, mit der wir den Inhalt eines Verzeichnisses ausgeben können. Dies sieht dann so aus.

<?php
function echodir($path = ".")
{
    
// Der Punkt ist das aktuelle Verzeichnis
    // .. kennt man als "Verzeichnis höher"
    // dir/ als "Verzeichnis tiefer"
    
$dir = dir($path);
    while(
false !== ($file = $dir->read())) {
        echo
$path."/".$file."<br >\n";
    }
    
$dir->close();
}
?>

Dieses false !== muss dort stehen, da PHP sonst bei einer Datei mit den Namen 0 oder false die While-Schleife fälschlicherweise verlassen würde.

Die read-Methode ließt auch den Namen von Verzeichnissen aus. Wir können in diesem Script nicht erkennen, ob nun $file den Namen einer Datei oder den Namen eines Verzeichnisses zeigt. Aber natürlich hat PHP eine Funktion um sowas zu erkennen. Diese Funktion heißt is_dir. Mit der prüfen wir ob es sich um ein Unterverzeichnis handelt und dieses auch noch ausgeben wollen.

<?php
    
function echodir($path = ".")
    {
        
// Der Punkt ist das aktuelle Verzeichnis
        // .. kennt man als "Verzeichnis höher"
        // dir/ als "Verzeichnis tiefer"
        
$dir = dir($path);
        while(
false !== ($file = $dir->read())) {
            if(
is_dir($path."/".$file)) {
                
echodir($path."/".$file);
            } else {
                echo
$path."/".$file."<br >\n";
            }
        }
        
$dir->close();
    }
?>

Nun können wir uns das Listing eines Verzeichnisses mit allen Unterverzeichnissen anzeigen lassen. Wenn wir diesen Programmcode ausführen, kann es sein das PHP abschmiert. Denn bei diesem Listing werden auch die 'Verzeichnisse' . und .. erfasst. Und anstatt PHP immer tiefer geht und die Unterverzeichnisse ausgibt, kommt PHP durch den Punkt (=aktuelles Verzeichnis) nicht von der Stelle bzw. geht durch den zweifachen Punkt (=Verzeichnis höher) immer ein Verzeichnis höher. Deswegen müssen wir noch eine If-Abfrage schreiben, die diese Pfade ignoriert. Diese If-Abfrage hat man bestimmt irgentwo mal gesehen, aber nie verstanden.

<?php
    
function echodir($path = ".")
    {
        
// Der Punkt ist das aktuelle Verzeichnis
        // .. kennt man als "Verzeichnis höher"
        // dir/ als "Verzeichnis tiefer"
        
$dir = dir($path);
        while(
false !== ($file = $dir->read()))
        {
            if((
"."  == $file) OR
               (
".." == $file))
                continue;
            if(
is_dir($path."/".$file)) {
                
echodir($path."/".$file);
            } else {
                echo(
$path."/".$file."<br >\n");
            }
        }
        
$dir->close();
    }
?>

Achtet auch darauf, dass die Verzeichnisse keine Symbolischen Links auf höherliegende Verzeichnisse hat, dann haben wir das selbe Problem. Diesem kann man aber mit is_link vorbeugen.

Nun kann man die Verzeichnisse ausgeben lassen.

<?php
    
echo "Im aktuellen Verzeichnis liegt: <br />\n";
    
echodir();
    echo
"In /etc liegt: <br />\n";
    
echodir('/etc');
?>

Beachtet, dass unter Windows die Verzeichnisse mit \ getrennt werden, in Unixsystem hingegen mit /.

6. Fibonacci-Zahlen

Es gibt in der Mathematik die sogenannten Fibonacci-Zahlen. Diese Zahlenfolge sieht so aus.

1 1 2 3 5 8 13 21 34 55 89 144 ...
        

Die nächste Zahl wird gebildet durch die Summe der beiden vorher stehenden Zahlen. Am Anfang stehen zwei einsen, dies ist der Start und in den Programmiersprachen die Abbruchbedingung der Rekursion.

1 + 1 = 2
    1 + 2 = 3
        2 + 3 = 5
            3 + 5 = 8
                5 + 8 = 13
                    ...
        

Formelmäßig sind die Fibonacci Zahle so definiert.

fb(x) = fb(x-1) + (fb(x-2)
fb(0) = 1
fb(1) = 1
        

In PHP sieht die Funktion nun so aus.

<?php
    
function fibo($zahl = 0)
    {
        
$zahl = (int)$zahl;
        if(
$zahl < 0) {
            
$zahl = 0;
        }
        switch(
$zahl) {
        case
0:
        case
1:
            return
1;
            break;

        default:
            return
fibo($zahl-1) + fibo($zahl-2);
            break;

        }
    }
?>

Diese Funktion kann dann ganz normal aufgerufen.

<?php
    
for($i=1; $i<=15; $i++) {
        echo
$i". Fibonacci Zahl: ".fibo($i)."<br />\n";
    }
?>

Diese Art der Berechnung der Fibonaccizahlen hat eine exponentielle steigende Laufzeit, je nach dem welche Fibonaccizahl man berechnen möchte. Deshalb gibt es auch eine interative Formel zur berechnung der Fibonaccizahlen, die bei weitem schneller läuft als diese Rekursive Funktion.

7. Taschenrechner

Wir schreiben nun mal ein kleines Programm, das ein Rechenterm ausführt. Der Benutzer gibt einen Term ein und PHP rechnet diesen dann aus. Um es einfach zu halten benutzen wir nur die Addition und Multiplikation. So könnten Beispieleingaben vom Benutzer aussehen.

1+2
3+5*6+7
4*5*6*7*8+3
        

Solche eingaben lösen wir dann Rekursiv. Wir suchen dann unser Operationszeichen und behandeln dann den linken und rechten Teil entsprechend, z.B. addieren. Wenn aber der linke und/oder der rechte Teil wieder eine Rechenoperation enthält muss diese wieder ausgerechnet werden. Und dies ist dann unsere Rekursion.

<?php
    
function parseterm($string)
    {
        
// ...
    
}
?>

Das ist nun unser Programmkopf. Wir suchen nun nach einem Plus- oder Malzeichen. Dies machen wir mit einem Regex, können aber auch mit den String-Funktionen wie strstr und explode hantieren.

<?php
    
function parseterm($string)
    {
        
$string = preg_replace('/\s/', '', $string);
        
// Whitespaces löschen

        
if(preg_match('/^\d+([+*]\d+)*/$', $string)) {
            
// erstmal nur ganze Zahlen mit Rechenoperationen
            // matchen

            // Pluszeichen suchen
            
if(preg_match('/^(.+?)\+(.+)$/', $string, $matches)) {
                
// der Erste Regexteil ist ungreedy, der zweite greedy
                
return(parseterm($matches[1]) + parseterm($matches[2]));
            } elseif(
preg_match('/^(.+?)\*(.+)$/', $string, $matches)) {
                return(
parseterm($matches[1]) * parseterm($matches[2]));
            } elseif(
preg_match('/^\d+$/', $string)) {
                return((int)
$string);
            } else {
                echo
"<p>\n";
                echo
"    Der zu untersuchende String ist nicht gültig:<br />\n";
                echo
$string;
                echo
"</p>\n";
                die();
            }
        } else {
            echo
"<p>\n";
            echo
"    Der String ist kein gültiger Ausdruck.\n";
            echo
"</p>\n";
            die();
        }
    }
?>

Ihr fragt euch bestimmt warum ich erst ein Pluszeichen suche und dann nach einem Malzeichen. Es gilt doch Punkt vor Strich.

Da habt ihr ja auch recht. Bei 2*3+4*5 wird die Addidition zuletzt durchgeführt. Denn er findet das Pluszeichen und wartet nun auf das Ergebnis der Teilterme. Diese werden dann im nächsten Schritt durch die Rekursion ausgerechnet. Hier ein Beispiel.

Eingabe: 4+5*3+6+7*5*3+4
        

Dies ist ...*kopfrechne*... 134. Mal gucken ob wir da hinkommen. PHP findet nun das erste Pluszeichen. Er musst das erste Pluszeichen matchen, weil der linke Teil durch das .+? so klein wie möglich sein muss.

Eingabe: 4+5*3+6+7*5*3+4
         4 + 5*3+6+7*5*3+4
        

Die Vier ist ein normaler Wert, den Returned er weiter. Der rechte Teil ist keine Zahl sondern ein Ausdruck bzw. Rechenterm. Dieser muss nun wieder durch die Rekursion geparsed werden. Dort findet er wieder ein Pluszeichen. Obwohl als erstes ein Malzeichen vorhanden ist, findet er das Pluszeichen, denn wir suchen ja auch zuerst ein Pluszeichen und finden es auch. Nun Teil er wieder diesen String.

Eingabe: 4+5*3+6+7*5*3+4
         4 + 5*3+6+7*5*3+4
         4 + 5*3 + 6+7*5*3+4
        

Nun rechnet er wieder den linken Teil aus, also das 5*3. Da dies auch wieder keine ganze Zahl ist, wird wieder die Rekursion aufgerufen.

Eingabe: 4+5*3+6+7*5*3+4
         4 + 5*3+6+7*5*3+4
         4 + 5*3 + 6+7*5*3+4
         4 + 5 * 3 + 5+7*5*3+4
        

Nun multipliziert er das Ergebnis.

Eingabe: 4+5*3+6+7*5*3+4
         4 + 5*3+6+7*5*3+4
         4 + 5*3 + 6+7*5*3+4
         4 + 5 * 3 + 5+7*5*3+4
         4 +   15  + 5+7*5*3+4
        

Nun spare ich mir mal die Kommentare.

Eingabe: 4+5*3+6+7*5*3+4
         4 + 5*3+6+7*5*3+4
         4 + 5*3 + 6+7*5*3+4
         4 + 5 * 3 + 6+7*5*3+4
         4 +   15  + 6+7*5*3+4
         4 +   15  + 6 + 7*5*3+4
         4 +   15  + 6 + 7*5*3 + 4
         4 +   15  + 6 + 7 * 5*3 + 4
         4 +   15  + 6 + 7 * 5 * 3 + 4
         4 +   15  + 6 + 7 *   15  + 4
         4 +   15  + 6 +    105    + 4
         4 +   15  + 6 +    105    + 4
         4 +   15  + 6 +      109
         4 +   15  +     115
         4 +        130
         134
        

Diese Funktion kann nun einen Rechenterm mit Addition und Multiplikationen ausrechnen. Mit einem eval wäre dies aber viel einfacher ;).

8. Fazit

Wann braucht man denn nun Rekursion? Dies braucht man, wenn man etwas verschachteltes ausgeben, bearbeiten oder löschen möchte. Oder wenn etwas von etwas anderem vom gleichen Typ abhängt. Rekursion ist ein interessantes Thema. Mit Google findet man jede Menge informationen dazu.

Fragen zum aktuellen Thema

  1. Worauf muss man bei Rekursion aufpassen?
Worauf muss man bei Rekursion aufpassen?

Wenn man eine Rekursionsfunktion schreibt, muss man darauf aufpassen, dass eine Abbruch-Bedinung vorhanden ist. Sonst läuft sich PHP fest und PHP beendet das Script.

Nach oben