W JavaScript funkcje zagnieżdżone są bardzo przydatne: domknięcia, metody prywatne i co masz ..
Do czego służą zagnieżdżone funkcje PHP? Czy ktoś ich używa i po co?
Oto małe dochodzenie, które przeprowadziłem
<?php
function outer( $msg ) {
function inner( $msg ) {
echo 'inner: '.$msg.' ';
}
echo 'outer: '.$msg.' ';
inner( $msg );
}
inner( 'test1' ); // Fatal error: Call to undefined function inner()
outer( 'test2' ); // outer: test2 inner: test2
inner( 'test3' ); // inner: test3
outer( 'test4' ); // Fatal error: Cannot redeclare inner()
php
nested-function
meouw
źródło
źródło
Odpowiedzi:
W zasadzie nie ma. Zawsze traktowałem to jako efekt uboczny parsera.
Eran Galperin myli się, sądząc, że te funkcje są w jakiś sposób prywatne. Są po prostu niezadeklarowane, dopóki nie
outer()
zostaną uruchomione. Nie mają też prywatnego zasięgu; zanieczyszczają zasięg globalny, choć są opóźnione. Jako wywołanie zwrotne, zewnętrzne wywołanie zwrotne nadal można było wywołać tylko raz. Nadal nie widzę, jak pomocne jest zastosowanie go do tablicy, która najprawdopodobniej wywołuje alias więcej niż raz.Jedynym przykładem „prawdziwego świata”, który mógłbym wykopać, jest ten , który można uruchomić tylko raz i można go przepisać jako czystszy, IMO.
Jedyne zastosowanie, jakie przychodzi mi do głowy, to wywoływanie przez moduły
[name]_include
metody, która ustawia kilka zagnieżdżonych metod w przestrzeni globalnej, w połączeniu zif (!function_exists ('somefunc')) { function somefunc() { } }
czeki.
OOP PHP byłoby oczywiście lepszym wyborem :)
źródło
def
deklaracje w RubimJeśli używasz PHP 5.3, możesz uzyskać bardziej podobne do Javacript zachowanie dzięki funkcji anonimowej:
<?php function outer() { $inner=function() { echo "test\n"; }; $inner(); } outer(); outer(); inner(); //PHP Fatal error: Call to undefined function inner() $inner(); //PHP Fatal error: Function name must be a string ?>
Wynik:
źródło
[Przepisano zgodnie z komentarzem @PierredeLESPINAY.]
To nie tylko efekt uboczny, ale w rzeczywistości bardzo przydatna funkcja do dynamicznego modyfikowania logiki twojego programu. Pochodzi z czasów proceduralnych PHP, ale może się również przydać w architekturach OO, jeśli chcesz zapewnić alternatywne implementacje niektórych samodzielnych funkcji w najprostszy możliwy sposób. (Chociaż OO jest lepszym wyborem przez większość czasu, jest to opcja, a nie mandat, a niektóre proste zadania nie wymagają dodatkowego okrucieństwa).
Na przykład, jeśli dynamicznie / warunkowo ładujesz wtyczki ze swojego frameworka i chcesz, aby życie autorów wtyczek było super łatwe, możesz zapewnić domyślne implementacje dla niektórych krytycznych funkcji, których wtyczka nie nadpisała:
<?php // Some framework module function provide_defaults() { // Make sure a critical function exists: if (!function_exists("tedious_plugin_callback")) { function tedious_plugin_callback() { // Complex code no plugin author ever bothers to customize... ;) } } }
źródło
Funkcje zdefiniowane w funkcjach, dla których nie widzę zbytniego zastosowania, ale funkcje zdefiniowane warunkowo - widzę. Na przykład:
if ($language == 'en') { function cmp($a, $b) { /* sort by English word order */ } } else if ($language == 'de') { function cmp($a, $b) { /* sort by German word order; yes it's different */ } } // etc
A potem wszystko, co musi zrobić twój kod, to użyć funkcji 'cmp' w takich rzeczach, jak wywołania usort (), aby nie zaśmiecać sprawdzania języka w całym kodzie. Nie zrobiłem tego, ale widzę argumenty przemawiające za tym.
źródło
Biorąc pod uwagę powyższe, można po prostu utworzyć zagnieżdżoną funkcję, aby zastąpić jakiś zlokalizowany, powtarzalny kod w funkcji (który będzie używany tylko wewnątrz funkcji nadrzędnej). Funkcja anonimowa jest tego doskonałym przykładem.
Niektórzy mogą powiedzieć, że po prostu utwórz metody prywatne (lub mniejsze bloki kodu) w klasie, ale to jest mętne, gdy bardzo specyficzne zadanie (które jest wyłączne dla rodzica) musi zostać zmodularyzowane, ale niekoniecznie dostępne dla reszty Klasa. Dobra wiadomość jest taka, że jeśli okaże się, że potrzebujesz tej funkcji gdzie indziej, poprawka jest raczej elementarna (przenieś definicję do bardziej centralnej lokalizacji).
Ogólnie rzecz biorąc, używanie JavaScript jako standardu do oceny innych języków programowania opartych na C jest złym pomysłem. JavaScript jest zdecydowanie własnym zwierzęciem w porównaniu z PHP, Pythonem, Perlem, C, C ++ i Javą. Oczywiście istnieje wiele podobieństw, ale drobiazgowe szczegóły (referencyjne JavaScript: The Definitive Guide, 6th Edition, Rozdziały 1-12 ) sprawiają, że rdzeń JavaScript jest wyjątkowy, piękny, inny, prosty i złożone w tym samym czasie. To moje dwa centy.
Żeby było jasne, nie twierdzę, że funkcje zagnieżdżone są prywatne. Właśnie to zagnieżdżanie może pomóc uniknąć bałaganu, gdy coś trywialnego wymaga modularyzacji (i jest potrzebne tylko funkcji nadrzędnej).
źródło
Całe moje php to OO, ale widzę zastosowanie dla funkcji zagnieżdżonych, szczególnie gdy twoja funkcja jest rekurencyjna i niekoniecznie jest obiektem. Oznacza to, że nie jest wywoływana poza funkcją, w której jest zagnieżdżona, ale jest rekurencyjna, a następnie musi być funkcją.
Tworzenie nowej metody do ekspresowego użycia jednej innej metody nie ma sensu. Dla mnie to niezgrabny kod i raczej nie jest to celem OO. Jeśli nigdy nie będziesz wywoływać tej funkcji nigdzie indziej, zagnieżdż ją.
źródło
Podczas wywoływania usług sieciowych okazało się, że jest to znacznie niższe obciążenie (pamięć i szybkość) dynamicznie, w tym w sposób zagnieżdżony, poszczególne funkcje w bibliotekach pełnych tysięcy funkcji. Typowy stos wywołań może mieć głębokość od 5 do 10 wywołań, tylko wymaganie dynamicznego łączenia kilkunastu plików o wielkości 1–2 KB było lepsze niż uwzględnienie megabajtów. Dokonano tego po prostu przez utworzenie niewielkiej funkcji opakowującej, której wymaga. Dołączone funkcje zostaną zagnieżdżone w funkcjach powyżej stosu wywołań. Rozważ to w przeciwieństwie do klas pełnych setek funkcji, które nie były wymagane przy każdym wywołaniu usługi sieciowej, ale mogły również wykorzystywać wbudowane funkcje php z opóźnionym ładowaniem.
źródło
jeśli jesteś w php 7, zobacz to: Ta implementacja da ci jasny obraz funkcji zagnieżdżonych. Załóżmy, że mamy trzy funkcje (too (), boo () i zoo ()) zagnieżdżone w funkcji foo (). boo () i zoo () mają tę samą nazwaną zagnieżdżoną funkcję xoo (). Teraz w tym kodzie wyraźnie zakomentowałem reguły funkcji zagnieżdżonych.
function foo(){ echo 'foo() is called'.'<br>'; function too(){ echo 'foo()->too() is called'.'<br>'; } function boo(){ echo 'foo()->boo() is called'.'<br>'; function xoo(){ echo 'foo()->boo()->xoo() is called'.'<br>'; } function moo(){ echo 'foo()->boo()->moo() is called'.'<br>'; } } function zoo(){ echo 'foo()->zoo() is called'.'<br>'; function xoo(){ //same name as used in boo()->xoo(); echo 'zoo()->xoo() is called'.'<br>'; } #we can use same name for nested function more than once #but we can not call more than one of the parent function } } /**************************************************************** * TO CALL A INNER FUNCTION YOU MUST CALL OUTER FUNCTIONS FIRST * ****************************************************************/ #xoo();//error: as we have to declare foo() first as xoo() is nested in foo() function test1(){ echo '<b>test1:</b><br>'; foo(); //call foo() too(); boo(); too(); // we can can a function twice moo(); // moo() can be called as we have already called boo() and foo() xoo(); // xoo() can be called as we have already called boo() and foo() #zoo(); re-declaration error //we cannont call zoo() because we have already called boo() and both of them have same named nested function xoo() } function test2(){ echo '<b>test2:</b><br>'; foo(); //call foo() too(); #moo(); //we can not call moo() as the parent function boo() is not yet called zoo(); xoo(); #boo(); re-declaration error //we cannont call boo() because we have already called zoo() and both of them have same named nested function xoo() }
Teraz, jeśli wywołamy test1 (), wynik będzie taki:
jeśli wywołasz test2 (), wynik będzie taki:
Ale nie możemy wywołać jednocześnie text1 () i test2 (), aby uniknąć błędu ponownej deklaracji
źródło
Wiem, że to stary post, ale fwiw Używam funkcji zagnieżdżonych, aby zapewnić schludne i uporządkowane podejście do wywołań rekurencyjnych, gdy potrzebuję funkcji tylko lokalnie - np. Do budowania obiektów hierarchicznych itp. (Oczywiście musisz uważać, że funkcja nadrzędna jest tylko zadzwoniono raz):
function main() { // Some code function addChildren ($parentVar) { // Do something if ($needsGrandChildren) addChildren ($childVar); } addChildren ($mainVar); // This call must be below nested func // Some more code }
Punktem uwagi w php w porównaniu z JS na przykład jest to, że wywołanie funkcji zagnieżdżonej musi być wykonane po, tj. Poniżej, deklaracji funkcji (w porównaniu z JS gdzie wywołanie funkcji może być gdziekolwiek w funkcji nadrzędnej
źródło
Tak naprawdę użyłem tej cechy tylko wtedy, gdy przydatne było wykonanie małej funkcji rekurencyjnej wewnątrz podstawowej, bardziej kategorycznej funkcji, ale nie chciałem przenosić jej do innego pliku, ponieważ było to fundamentalne dla zachowania podstawowego procesu. Zdaję sobie sprawę, że istnieją inne sposoby realizacji tego zadania, ale chcę się upewnić, że moi programiści widzą tę funkcję za każdym razem, gdy patrzą na mój parser, prawdopodobnie i tak powinni zmodyfikować ...
źródło
Zagnieżdżone funkcje są przydatne w Memoization (buforowanie wyników funkcji w celu poprawy wydajności).
<?php function foo($arg1, $arg2) { $cacheKey = "foo($arg1, $arg2)"; if (! getCachedValue($cacheKey)) { function _foo($arg1, $arg2) { // whatever return $result; } $result = _foo($arg1, $arg2); setCachedValue($cacheKey, $result); } return getCachedValue($cacheKey); } ?>
źródło
_foo()
co spowoduje błąd krytyczny.Funkcje zagnieżdżone są przydatne, jeśli chcesz, aby funkcja zagnieżdżona korzystała ze zmiennej zadeklarowanej w funkcji nadrzędnej.
<?php ParentFunc(); function ParentFunc() { $var = 5; function NestedFunc() { global $var; $var = $var + 5; return $var; }; echo NestedFunc()."<br>"; echo NestedFunc()."<br>"; echo NestedFunc()."<br>"; } ?>
źródło