Domanda

In JavaScript le funzioni nidificate sono molto utili: chiusure, metodi privati ??e cosa hai ..

A cosa servono le funzioni PHP nidificate? Qualcuno li usa e per cosa?

Ecco una piccola indagine che ho fatto

<?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()
È stato utile?

Soluzione

Non ce n'è praticamente nessuno, l'ho sempre trattato come un effetto collaterale del parser.

Eran Galperin ha torto che queste funzioni sono in qualche modo private, sono semplicemente dichiarate fino a quando non viene eseguito outer () . Inoltre, non hanno scopi privati, ma inquinano l'ambito globale seppur in ritardo. E come callback il callback esterno poteva ancora essere chiamato solo una volta. Non vedo ancora come sia utile applicarlo su un array che molto probabilmente chiama l'alias più di una volta.

L'unico esempio di "mondo reale" che ho potuto approfondire è this che può essere eseguito una sola volta e potrebbe essere riscritto più pulito IMO.

L'unico uso che mi viene in mente è che i moduli chiamino un metodo _include [nome] che imposta diversi metodi nidificati nello spazio globale combinato con

if (!function_exists ('somefunc')) {
  function somefunc() { }
}

controlli.

L'OPP di PHP sarebbe ovviamente una scelta migliore :)

Altri suggerimenti

Se stai usando PHP 5.3 puoi ottenere un comportamento più simile a Javascript con una funzione anonima:

<?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
?>

Output:

test
test

[Riscritto secondo il commento di @PierredeLESPINAY.]

Non è affatto solo un effetto collaterale, ma in realtà una funzione molto utile per modificare dinamicamente la logica del tuo programma. È dai tempi procedurali di PHP, ma può tornare utile anche con le architetture OO, se si desidera fornire implementazioni alternative per determinate funzioni autonome nel modo più semplice possibile. (Mentre OO è la scelta migliore per la maggior parte del tempo, è un'opzione, non un mandato, e alcune semplici attività non richiedono l'innesto extra.)

Ad esempio, se si caricano dinamicamente / condizionatamente plug-in dal proprio framework e si desidera semplificare la vita degli autori dei plug-in, è possibile fornire implementazioni predefinite per alcune funzioni critiche che il plug-in non ha ignorato:

<?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... ;)
        }
    }
}

Funzioni definite all'interno di funzioni per le quali non riesco a vedere molto, ma che posso definire condizionalmente. Ad esempio:

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

E quindi tutto ciò che il tuo codice deve fare è usare la funzione 'cmp' in cose come le chiamate usort () in modo da non sporcare i controlli della lingua su tutto il codice. Ora non l'ho fatto ma posso vedere gli argomenti per farlo.

Detto questo, si potrebbe semplicemente creare una funzione nidificata per sostituire un codice ripetitivo localizzato all'interno di una funzione (che verrà utilizzata solo all'interno della funzione genitore). Una funzione anonima ne è un perfetto esempio.

Qualcuno potrebbe dire semplicemente di creare metodi privati ??(o blocchi di codice più piccoli) in una classe, ma ciò sta confondendo le acque quando un'attività ultra specifica (che è esclusiva del genitore) deve essere modulare, ma non necessariamente disponibile per il resto di una classe. La buona notizia è che si scopre che hai bisogno di quella funzione altrove, la correzione è piuttosto elementare (sposta la definizione in una posizione più centrale).

In generale, usare JavaScript come standard con cui valutare altri linguaggi di programmazione basati su C è una cattiva idea. JavaScript è sicuramente il suo stesso animale rispetto a PHP, Python, Perl, C, C ++ e Java. Certo, ci sono molte somiglianze generali, ma i dettagli nitidi e grintosi (riferimento JavaScript: The Definitive Guide, 6th Edition, Chapters 1-12 ), quando prestati attenzione, rendono il core JavaScript unico, bello, diverso, semplice e complesso allo stesso tempo. Sono i miei due centesimi.

Giusto per essere chiari, non sto dicendo che le funzioni nidificate siano private. Solo questo annidamento può aiutare a evitare il disordine quando qualcosa di banale deve essere modulare (ed è necessario solo per la funzione genitore).

Tutto il mio php è OO, ma vedo un uso per le funzioni nidificate, in particolare quando la tua funzione è ricorsiva e non necessariamente un oggetto. Vale a dire, non viene chiamato al di fuori della funzione in cui è nidificato, ma è ricorsivo e successivamente deve essere una funzione.

È inutile creare un nuovo metodo per l'uso espresso di un altro metodo. Per me questo è un codice goffo e una specie di non punto di OO. Se non chiamerai mai quella funzione da nessun'altra parte, annidala.

Nella chiamata al servizio web lo abbiamo trovato un overhead molto più basso (memoria e velocità) che includeva dinamicamente in modo nidificato, singole funzioni su librerie piene di migliaia di funzioni. Lo stack di chiamate tipico potrebbe essere compreso tra 5 e 10 chiamate e richiedere solo il collegamento dinamico di una dozzina di file da 1-2kb era meglio che includere megabyte. Questo è stato fatto semplicemente creando una funzione util che richiede il wrapping. Le funzioni incluse diventano nidificate all'interno delle funzioni sopra lo stack di chiamate. Consideralo in contrasto con le classi piene di centinaia di funzioni che non erano richieste ad ogni chiamata al servizio web ma che avrebbero anche potuto usare le funzionalità integrate di caricamento pigro di php.

So che questo è un vecchio post, ma in seguito utilizzo le funzioni nidificate per fornire un approccio ordinato e ordinato a una chiamata ricorsiva quando ho solo bisogno della funzionalità localmente, ad es. per la costruzione di oggetti gerarchici ecc. (ovviamente devi fare attenzione che la funzione genitore sia chiamata una sola volta):

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
}

Un punto degno di nota in php rispetto ad esempio a JS è che la chiamata alla funzione nidificata deve essere effettuata dopo, cioè sotto, la dichiarazione di funzione (rispetto a JS dove la chiamata di funzione può trovarsi ovunque all'interno della funzione genitore

se sei in php 7, vedi questo: Questa implementazione ti darà un'idea chiara della funzione nidificata. Supponiamo di avere tre funzioni (too (), boo () e zoo ()) nidificate nella funzione foo (). boo () e zoo () hanno la stessa funzione nidificata xoo (). Ora in questo codice ho commentato chiaramente le regole delle funzioni nidificate.

   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()

    }

Ora se chiamiamo test1 () l'output sarà questo:

test1:
foo() is called
foo()->too() is called
foo()->boo() is called
foo()->too() is called
foo()->boo()->moo() is called
foo()->boo()->xoo() is called

se chiamiamo test2 () l'output sarà questo:

test2:
foo() is called
foo()->too() is called
foo()->zoo() is called
zoo()->xoo() is called

Ma non possiamo chiamare sia text1 () che test2 () allo stesso tempo per evitare errori di ri-dichiarazione

Ho usato davvero questa caratteristica solo quando era utile eseguire una piccola funzione ricorsiva all'interno di una funzione primaria, più categorica, ma non volevo spostarla in un file diverso perché era fondamentale per il comportamento di una primaria processi. Mi rendo conto che ci sono altre "migliori pratiche" modi per farlo, ma voglio assicurarmi che i miei sviluppatori vedano quella funzione ogni volta che guardano il mio parser, è probabile che cosa dovrebbero comunque modificare ...

Le funzioni nidificate sono utili in Memoization (risultati della funzione di memorizzazione nella cache per migliorare le prestazioni).

<?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);
}
?>

Le funzioni nidificate sono utili se si desidera che la funzione nidificata utilizzi una variabile dichiarata all'interno della funzione padre.

<?php
ParentFunc();
function ParentFunc()
{
  $var = 5;
  function NestedFunc()
  {
    global $var;
    $var = $var + 5;
    return $var;
  };
  echo NestedFunc()."<br>";
  echo NestedFunc()."<br>";
  echo NestedFunc()."<br>";
}
?>
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top