¿Para qué son las funciones anidadas de PHP?
nested-function (10)
En JavaScript las funciones anidadas son muy útiles: cierres, métodos privados y lo que tienes ..
¿Para qué son 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()
Básicamente no existe, siempre he tratado esto como un efecto secundario del analizador sintáctico.
Eran Galperin se confunde con que estas funciones son de alguna manera privadas, simplemente no se declaran hasta que se ejecuta outer()
. Tampoco tienen un alcance privado, sí contaminan el alcance global aunque se retrasen. Y como una devolución de llamada, la devolución de llamada externa solo podría ser llamada 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 podría desenterrar es this que solo puede ejecutarse una vez y podría reescribirse como una IMO más limpia.
El único uso que se me ocurre es que los módulos llamen a un método [nombre] _include que establece varios métodos anidados en el espacio global combinado con
if (!function_exists (''somefunc'')) {
function somefunc() { }
}
cheques.
PHP OOP obviamente sería una mejor opción :)
Dicho todo lo anterior, uno podría simplemente crear una función anidada para reemplazar algún código localizado y repetitivo dentro de una función (que solo se usará dentro de la función principal). Algunos podrían decir simplemente crear métodos privados (o bloques de código más pequeños), 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 la clase ( o el espacio global en un programa de procedimiento). La buena noticia es que si 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 ( JavaScript de referencia : The Definitive Guide, 6th Edition, Chapters 1-12 ), cuando se les presta atención, hacen que el JavaScript central sea único, hermoso, diferente, simple y complejo todo al mismo tiempo. Esos son mis dos centavos.
Para ser claros, no estoy diciendo que las funciones anidadas sean privadas. Solo que anidar puede ayudar a evitar el desorden cuando algo trivial necesita ser modularizado (y solo es necesario para la función principal).
En las llamadas al servicio web encontramos una sobrecarga (memoria y velocidad) mucho más baja de forma dinámica, incluida de forma anidada, funciones individuales sobre bibliotecas llenas de miles de funciones. La pila de llamadas típica puede estar entre 5 y 10 llamadas de profundidad, solo requiere vincular una docena de archivos de 1-2 kb dinámicamente, es mejor que incluir megabytes. Esto se hizo simplemente creando una pequeña función que el envoltorio requiere. Las funciones incluidas se anidan dentro de las funciones sobre la pila de llamadas. Considérelo en contraste con las clases llenas de cientos de funciones que no se requerían en cada llamada al servicio web, pero que también podrían haber utilizado las funciones integradas de carga lenta de php.
Funciones definidas dentro de funciones para las que no veo mucho uso, pero sí funciones definidas condicionalmente. 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 entonces todo lo que su código necesita hacer es usar la función ''cmp'' en cosas como llamadas a usort () para que no arroje las verificaciones de idioma en todo su código. Ahora no he hecho esto, pero puedo ver argumentos para hacerlo.
Las funciones anidadas son útiles en Memoization (resultados de la función de almacenamiento en caché 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);
}
?>
Las funciones anidadas son útiles si desea que la función anidada utilice una variable que se declaró dentro de la función primaria.
<?php
ParentFunc();
function ParentFunc()
{
$var = 5;
function NestedFunc()
{
global $var;
$var = $var + 5;
return $var;
};
echo NestedFunc()."<br>";
echo NestedFunc()."<br>";
echo NestedFunc()."<br>";
}
?>
Sé que esta es una publicación anterior, pero utilizo funciones anidadas para dar un enfoque limpio 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 sea 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 de nota en php comparado 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 de función puede estar en cualquier lugar dentro de la función padre
Si está utilizando PHP 5.3, puede obtener un comportamiento 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:
test
test
Todo mi php es OO, pero veo un uso para funciones anidadas, particularmente cuando tu función es recursiva y no necesariamente un objeto. Es decir, no se llama fuera de la función en la que está anidada, pero es recursiva y posteriormente necesita ser una función.
No tiene mucho sentido crear un nuevo método para el uso expreso de otro método único. Para mí, ese es un código torpe y no es el objetivo de OO. Si nunca va a llamar a esa función en ningún otro lado, anídela.
[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 a partir de los días de procedimiento de PHP, pero también puede ser útil con las arquitecturas de OO, si desea proporcionar implementaciones alternativas para ciertas funciones independientes de la manera más directa posible. (Mientras que OO es la mejor opción la mayor parte del tiempo, es una opción, no un mandato, y algunas tareas simples no necesitan la parte extra).
Por ejemplo, si carga plugins dinámicamente / condicionalmente desde su estructura y desea hacer que la vida de los autores de los complementos sea muy sencilla, 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... ;)
}
}
}