En JavaScript las funciones anidadas son muy útiles: cierres, métodos privados y lo que tengas.
¿Para qué sirven las funciones PHP anidadas? ¿Alguien los usa y para qué?
Aquí hay una pequeña investigación que hice
<?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
maullar
fuente
fuente
Respuestas:
Básicamente, no hay ninguno. Siempre he tratado esto como un efecto secundario del analizador.
Eran Galperin se equivoca al pensar que estas funciones son de alguna manera privadas. Simplemente no se declaran hasta que
outer()
se ejecutan. Tampoco tienen un alcance privado; contaminan el ámbito mundial, aunque con retraso. Y como devolución de llamada, la devolución de llamada externa solo se puede llamar una vez. Todavía no veo cómo es útil aplicarlo en una matriz, que muy probablemente llama al alias más de una vez.El único ejemplo del 'mundo real' que pude desenterrar es este , que solo puede ejecutarse una vez y podría reescribirse más limpio, en mi opinión.
El único uso que se me ocurre es que los módulos llamen a un
[name]_include
método, que establece varios métodos anidados en el espacio global, combinados conif (!function_exists ('somefunc')) { function somefunc() { } }
cheques.
OOP de PHP obviamente sería una mejor opción :)
fuente
def
declaraciones en RubySi está utilizando PHP 5.3, puede obtener un comportamiento más similar a Javacript con una función anónima:
<?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 ?>
Salida:
fuente
[Reescrito según el comentario de @PierredeLESPINAY.]
No es solo un efecto secundario, sino una característica muy útil para modificar dinámicamente la lógica de su programa. Es de los días de PHP procedimental, pero también puede ser útil con arquitecturas OO, si desea proporcionar implementaciones alternativas para ciertas funciones independientes de la manera más sencilla posible. (Si bien OO es la mejor opción la mayor parte del tiempo, es una opción, no un mandato, y algunas tareas simples no necesitan el esfuerzo adicional).
Por ejemplo, si carga complementos de forma dinámica / condicional desde su marco y desea facilitar la vida de los autores del complemento, puede proporcionar implementaciones predeterminadas para algunas funciones críticas que el complemento no anuló:
<?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... ;) } } }
fuente
Funciones definidas dentro de funciones para las que no veo mucho uso, pero las funciones definidas condicionalmente puedo. Por ejemplo:
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
Y luego, todo lo que debe hacer su código es usar la función 'cmp' en cosas como llamadas a usort () para que no ensucie las verificaciones de idioma en todo su código. Ahora no he hecho esto, pero puedo ver argumentos para hacerlo.
fuente
Dicho todo lo anterior, uno podría simplemente crear una función anidada para reemplazar algún código repetitivo localizado dentro de una función (que solo se usará dentro de la función principal). Una función anónima es un ejemplo perfecto de esto.
Algunos podrían decir simplemente crear métodos privados (o bloques de código más pequeños) en una clase, pero eso está enturbiando las aguas cuando una tarea ultraespecífica (que es exclusiva del padre) necesita ser modularizada, pero no necesariamente disponible para el resto de una clase. La buena noticia es que si resulta que necesita esa función en otro lugar, la solución es bastante elemental (mueva la definición a una ubicación más central).
En términos generales, usar JavaScript como estándar para evaluar otros lenguajes de programación basados en C es una mala idea. JavaScript es definitivamente su propio animal en comparación con PHP, Python, Perl, C, C ++ y Java. Por supuesto, hay muchas similitudes generales, pero los detalles esenciales (referencia JavaScript: La Guía Definitiva, 6a Edición, Capítulos 1-12 ), cuando se les presta atención, hacen que el núcleo de JavaScript sea único, hermoso, diferente, simple y complejo todo al mismo tiempo. Esos son mis dos centavos.
Para que quede claro, no estoy diciendo que las funciones anidadas sean privadas. Solo ese anidamiento puede ayudar a evitar el desorden cuando algo trivial necesita ser modularizado (y solo lo necesita la función principal).
fuente
Todo mi php es OO, pero veo un uso para funciones anidadas, particularmente cuando su función es recursiva y no necesariamente un objeto. Es decir, no se llama fuera de la función en la que está anidado, sino que es recursivo y, posteriormente, debe ser una función.
No tiene mucho sentido crear un nuevo método para el uso expreso de un solo otro método. Para mí, ese es un código torpe y, en cierto modo, no es el punto de OO. Si nunca va a llamar a esa función en ningún otro lugar, anímela.
fuente
En las llamadas al servicio web, encontramos una sobrecarga mucho menor (memoria y velocidad) que incluye dinámicamente, de manera anidada, funciones individuales sobre bibliotecas llenas de miles de funciones. La pila de llamadas típica puede tener entre 5 y 10 llamadas de profundidad, solo es necesario vincular una docena de archivos de 1 a 2 kb dinámicamente, era mejor que incluir megabytes. Esto se hizo simplemente creando una pequeña función útil que requiere el envoltorio. Las funciones incluidas se anidan dentro de las funciones encima de la pila de llamadas. Considérelo en contraste con las clases llenas de cientos de funciones que no eran necesarias en cada llamada de servicio web, pero que también podrían haber utilizado las funciones de carga diferida incorporadas de php.
fuente
si está en php 7, vea esto: Esta implementación le dará una idea clara sobre la función anidada. Supongamos que tenemos tres funciones (too (), boo () y zoo ()) anidadas en la función foo (). boo () y zoo () tienen la misma función anidada xoo (). Ahora en este código he comentado claramente las reglas de las funciones anidadas.
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() }
Ahora, si llamamos a test1 (), la salida será esta:
si llamamos test2 () la salida será esta:
Pero no podemos llamar a text1 () y test2 () al mismo tiempo para evitar un error de re-declaración
fuente
Sé que esta es una publicación antigua, pero primero uso funciones anidadas para dar un enfoque ordenado y ordenado a una llamada recursiva cuando solo necesito la funcionalidad localmente, por ejemplo, para construir objetos jerárquicos, etc. (obviamente, debe tener cuidado de que la función principal es solo llamado una vez):
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 a tener en cuenta en php en comparación con JS, por ejemplo, es que la llamada a la función anidada debe realizarse después, es decir, debajo de la declaración de la función (en comparación con JS, donde la llamada a la función puede estar en cualquier lugar dentro de la función principal
fuente
Realmente solo he usado esta característica cuando era útil para ejecutar una pequeña función recursiva dentro de una función primaria, más categórica, pero no quería moverla a un archivo diferente porque era fundamental para el comportamiento de un proceso primario. Me doy cuenta de que hay otras formas de "mejores prácticas" para hacer esto, pero quiero asegurarme de que mis desarrolladores vean esa función cada vez que miran mi analizador, es probable que sea lo que deberían modificar de todos modos ...
fuente
Las funciones anidadas son útiles en Memoization (almacenar en caché los resultados de la función para mejorar el rendimiento).
<?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); } ?>
fuente
_foo()
lo que resultará en un error fatal.Las funciones anidadas son útiles si desea que la función anidada utilice una variable que se declaró dentro de la función principal.
<?php ParentFunc(); function ParentFunc() { $var = 5; function NestedFunc() { global $var; $var = $var + 5; return $var; }; echo NestedFunc()."<br>"; echo NestedFunc()."<br>"; echo NestedFunc()."<br>"; } ?>
fuente