Funktion innerhalb einer Funktion.

71

Dieser Code erzeugt das Ergebnis als 56.

function x ($y) {
    function y ($z) {
        return ($z*2);
    }

    return($y+3);
}

$y = 4;
$y = x($y)*y($y);
echo $y;

Irgendeine Idee, was drinnen ist? Ich bin verwirrt.

Posto
quelle
26
Klingt nach einer Hausaufgabenfrage, ist aber immer noch eine gute Frage, haha.
hobbes3

Antworten:

97

X gibt zurück (Wert +3), während Y zurückgibt (Wert * 2)

Bei einem Wert von 4 bedeutet dies (4+3) * (4*2) = 7 * 8 = 56.

Obwohl der Umfang der Funktionen nicht eingeschränkt ist (was bedeutet, dass Sie Funktionsdefinitionen sicher verschachteln können), ist dieses Beispiel fehleranfällig:

1) Sie können y()vor dem Aufruf nicht aufrufen x(), da die Funktion y()erst x()nach einmaliger Ausführung definiert wird.

2) Ein x()zweimaliger Aufruf führt dazu, dass PHP die Funktion neu deklariert y(), was zu einem schwerwiegenden Fehler führt:

Schwerwiegender Fehler: y () kann nicht neu deklariert werden

Die Lösung für beide wäre, den Code so aufzuteilen, dass beide Funktionen unabhängig voneinander deklariert werden:

function x ($y) 
{
  return($y+3);
}

function y ($z)
{
  return ($z*2);
}

Dies ist auch viel besser lesbar.

Duroth
quelle
57
Ein weiterer Unterschied besteht darin, dass, wenn Sie die Funktion y in der Funktion x haben und die Funktion x zweimal aufrufen, ein Fehler beim erneuten Deklarieren der Funktion y angezeigt wird. (Wenn Sie dies wirklich brauchen, müssen Sie die Funktion y mit einer Überprüfung auf if (function_exists ('y')) {...) umgeben
Eugene M
3
@ Eugene M: Das habe ich noch nie gewusst. Danke, dass du darauf hingewiesen hast! (
Habe
4
"Das bedeutet, dass Sie Funktionsdefinitionen sicher" verschachteln "können, während Sie sie dennoch an einer beliebigen Stelle in der Datei aufrufen können" - das ist eine schreckliche Spracheigenschaft.
Michael
2
Michael, du kannst die anonyme Funktion verwenden, sie einer Variablen zuweisen und genießen, sie wird in ihrem Umfang begrenzt sein. @Duroth, Sie können auch vermeiden, Fehler erneut zu deklarieren, wenn Sie anonyme Funktionen verwenden.
Jewgenij Afanasjew
Der Funktionsumfang innerhalb der Funktion ist also immer noch global (innerhalb des Namespace der Datei, in der sie definiert ist)?
Jason
29
(4+3)*(4*2) == 56

Beachten Sie, dass PHP "verschachtelte Funktionen" nicht wirklich unterstützt, wie dies nur im Bereich der übergeordneten Funktion definiert ist. Alle Funktionen sind global definiert. Siehe die Dokumente .

Lukáš Lalinský
quelle
Danke, damit die innere Funktion nicht aufgerufen wird.
Posto
1
Wenn X aufgerufen wird, wird die innere Funktion definiert - nicht aufgerufen. Also das Ergebnis. Das ist der haarige Teil über Funktionen in Funktionen =)
Mauris
@ Lukas - Ich wette, der Fragesteller bezog sich auf den Teil, wenn die Funktion in y()istx()
Mauris
Na ja, dann sollte ich mich auf die gleichen Dokumente beziehen, in denen auch die Syntax zum Aufrufen von Funktionen erläutert wird . :)
Lukáš Lalinský
16

Ich bin mir nicht sicher, was der Autor dieses Codes erreichen wollte. Das Definieren einer Funktion innerhalb einer anderen Funktion bedeutet NICHT, dass die innere Funktion nur innerhalb der äußeren Funktion sichtbar ist. Nach dem ersten Aufruf von x () befindet sich die Funktion y () ebenfalls im globalen Bereich.

Anti Veeranna
quelle
2
Wenn Sie y () in x () definieren, kann x () nur einmal aufgerufen werden. Beim zweiten Aufruf von x () wird der schwerwiegende Fehler "Funktion bereits definiert" angezeigt.
Anti Veeranna
8

Dies ist ein nützliches Konzept für die Rekursion ohne statische Eigenschaften, Referenz usw.:

function getRecursiveItems($id){
    $allItems = array();
    
    function getItems($parent_id){
       return DB::findAll()->where('`parent_id` = $parent_id');
    } 
   
    foreach(getItems($id) as $item){
         $allItems = array_merge($allItems, getItems($item->id) );
    }

    return $allItems;
}
d.raev
quelle
Erklären? Sieht rekursiv aus, aber ich sehe es nicht. Befindet sich "getReqursiveItems" in getItems ()?
Josiah
1
@ Josiah nicht sicher, was meine ursprüngliche Idee hier war .. aber ich habe die Antwort bearbeitet, um einen möglichen Anwendungsfall zu zeigen.
d.raev
3
Dies scheint überhaupt nicht rekursiv zu sein, sondern es gibt alle Enkel des Originals zurück$id
KnightHawk
Wenn Sie zum ersten Mal ersetzen getItemsin foreachmit getItemmsund zweiten getItemsmit getReqursiveItemsIhnen rekursive Funktion erhalten.
przemo_li
5

Es ist möglich, eine Funktion aus einer anderen Funktion heraus zu definieren. Die innere Funktion existiert erst, wenn die äußere Funktion ausgeführt wird.

echo function_exists("y") ? 'y is defined\n' : 'y is not defined \n';
$x=x(2);
echo function_exists("y") ? 'y is defined\n' : 'y is not defined \n';

Ausgabe

y ist nicht definiert

y ist definiert

Einfache Sache, Sie können die Funktion y nicht aufrufen, bevor x ausgeführt wird

Nanhe Kumar
quelle
3

Ihre Anfrage macht 7 * 8

x(4) = 4+3 = 7 und y(4) = 4*2 = 8

Wenn die Funktion x aufgerufen wird, wird die Funktion y erstellt und nicht ausgeführt.

Mike Valstar
quelle
1
Ich wollte nur hinzufügen, dass dies keine wirklich gute Praxis ist. Sie werden auch feststellen, dass wenn Sie $ y = y ($ y) * x ($ y) verwenden; dass der Code stirbt, weil x nicht erstellt wurde. Eine solche Codierung führt nur zu Fehlern und Verwirrung.
Michael Mior
ja das stimmt; persönlich habe ich dies in der Praxis nur einmal verwendet, um für verschiedene Arten von magischen Zitaten einzutreten. obwohl das in einer if-Anweisung anstelle einer Funktion () war
Mike Valstar
0

Funktionen innerhalb einer Funktion oder sogenannte verschachtelte Funktionen sind sehr nützlich, wenn Sie einige Rekursionsprozesse ausführen müssen, z. B. das Schleifen einer echten Mehrfachschicht eines Arrays oder eines Dateibaums ohne mehrere Schleifen, oder manchmal verwende ich sie, um das Erstellen von Klassen für kleine Jobs zu vermeiden, die geteilt werden müssen und Isolieren der Funktionalität zwischen mehreren Funktionen. Aber bevor Sie sich für verschachtelte Funktionen entscheiden, müssen Sie das verstehen

  1. Die untergeordnete Funktion ist nur verfügbar, wenn die Hauptfunktion ausgeführt wird
  2. Sobald die Hauptfunktion ausgeführt wurde, können die untergeordneten Funktionen global aufgerufen werden
  3. Wenn Sie die Hauptfunktion zweimal aufrufen müssen, wird versucht, die untergeordnete Funktion neu zu definieren. Dies führt zu einem schwerwiegenden Fehler

Bedeutet dies, dass Sie keine verschachtelten Funktionen verwenden können? Nein, Sie können mit den folgenden Problemumgehungen

Die erste Methode besteht darin, die untergeordnete Funktion zu blockieren, die erneut in den globalen Funktionsstapel deklariert wird, indem ein bedingter Block mit vorhandener Funktion verwendet wird. Dadurch wird verhindert, dass die Funktion mehrmals im globalen Funktionsstapel deklariert wird.

function myfunc($a,$b=5){
    if(!function_exists("child")){
        function child($x,$c){
            return $c+$x;   
        }
    }
    
    try{
        return child($a,$b);
    }catch(Exception $e){
        throw $e;
    }
    
}

//once you have invoke the main function you will be able to call the child function
echo myfunc(10,20)+child(10,10);

und die zweite Methode besteht darin, den Funktionsumfang von child auf local anstatt auf global zu beschränken. Dazu müssen Sie die Funktion als anonyme Funktion definieren und einer lokalen Variablen zuweisen. Dann ist die Funktion nur im lokalen Bereich und verfügbar wird jedes Mal neu deklariert und aufgerufen, wenn Sie die Hauptfunktion aufrufen.

function myfunc($a,$b=5){
    $child = function ($x,$c){
        return $c+$x;   
    };
    
    try{
        return $child($a,$b);
    }catch(Exception $e){
        throw $e;
    }
    
}

echo myfunc(10,20);

Denken Sie daran, dass das untergeordnete Element nicht außerhalb der Hauptfunktion oder des globalen Funktionsstapels verfügbar ist

Aylian Craspa
quelle