2010-01-22 18 views
19

Sé que esta pregunta parece hacky y raro, pero hay una manera de eliminar una función en tiempo de ejecución en PHP?Extracción de una función en tiempo de ejecución en PHP

que tienen una función recursiva declarada en un bloque "if" y quieren que la función sea "válido" sólo en ese bloque "if". No quiero que esta función sea llamada fuera de este bloque.

Encontré runkit_function_remove pero runkit no está habilitado en mi host de web. ¿Hay alguna otra forma de hacer eso?

Por cierto que sólo el soporte de PHP 5.1.0.

Editar: sabía que mi pregunta era hacky pero aquí es exactamente lo que quiero hacer:

if (function_exists('get_magic_quotes_gpc') && @get_magic_quotes_gpc()) 
{ 
    function stripslashes_deep($value) 
    { 
     return is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value); 
    } 

    $_POST = array_map('stripslashes_deep', $_POST); 
    $_GET = array_map('stripslashes_deep', $_GET); 
    $_COOKIE = array_map('stripslashes_deep', $_COOKIE); 
    $_REQUEST = array_map('stripslashes_deep', $_REQUEST); 

    //runkit_function_remove('stripslashes_deep'); 
} 

Desde "stripslashes_deep" sólo se vivo cuando Cotizaciones mágicas están en ON, quería deshazte de él cuando haya terminado con él. No quiero que la gente confíe en una función que no siempre es allí. Espero que esté más claro ahora. ¡Las sugerencias de soluciones no-hacky son bienvenidas también!

+3

¿Por qué no puedes ** simplemente no llamarlo **? –

+0

¿No llamas a qué? – AlexV

+2

¡Ten cuidado! Las teclas de matriz también están recortadas por comillas mágicas. –

Respuesta

18

Desde el PHP Manual on Functions:

Todas las funciones y clases en PHP tienen el alcance mundial - se les puede llamar fuera de una función, incluso si se definieron en el interior y viceversa. [...] PHP no admite la sobrecarga de funciones, ni tampoco es posible definir o redefinir funciones declaradas previamente.

La excepción es a través de runkit. Sin embargo, puede definir su función como anonymous function y unset después de ejecutarla, p.

if (function_exists('get_magic_quotes_gpc') && @get_magic_quotes_gpc()) 
    $fn = create_function('&$v, $k', '$v = stripslashes($v);'); 
    array_walk_recursive(array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST), $fn); 
    unset($fn); 
} 

Algunos comentaristas señalaron correctamente (pero no un problema por más tiempo en PHP hoy en día), no se puede llamar a una función anónima dentro de sí mismo. Al usar array_walk_recursive puede evitar esta limitación. Personalmente, solo crearía una función regular y no me molestaría en eliminarla. No lastimará a nadie. Solo dale un nombre propio, como stripslashes_gpc_callback.

Nota: editado y condensado después de los comentarios

+0

Es una solución "estrafalaria", pero me gusta. Si el OP insiste en usar una función, esta es la manera de hacerlo. –

+0

¿Es posible hacer una función anónima recursiva? – AlexV

+0

Buen punto.No puedo pensar en una forma de hacer que esto funcione con recursión (sin básicamente volver al código que ya tienes). En ese caso, solo escuche sus ediciones (y las mías) y no se preocupe por eliminar la función. –

3

Respuesta simple: no.

Sin embargo, puede intentar colocar la función dentro de un espacio de nombres, una clase o incluso dentro de otra función - pero creo que eso no es lo que estás buscando.

Otra opción que tiene es usar debug_backtrace() dentro de dicha función para comprobar qué archivo/línea/etc ... lo está llamando - es hackish, lo sé, pero también lo es runkit_function_remove().


Editar - Lástima que no se quede PHP 5.3+, de lo contrario usted podría hacer:

if (get_magic_quotes_gpc()) 
{ 
    $_GET = json_decode(stripslashes(json_encode($_GET, JSON_HEX_APOS)), true); 
    $_POST = json_decode(stripslashes(json_encode($_POST, JSON_HEX_APOS)), true); 
    $_COOKIE = json_decode(stripslashes(json_encode($_COOKIE, JSON_HEX_APOS)), true); 
    $_REQUEST = json_decode(stripslashes(json_encode($_REQUEST, JSON_HEX_APOS)), true); 
} 

Para versiones anteriores de PHP you still have this option:

if (get_magic_quotes_gpc()) { 
    $process = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST); 
    while (list($key, $val) = each($process)) { 
     foreach ($val as $k => $v) { 
      unset($process[$key][$k]); 
      if (is_array($v)) { 
       $process[$key][stripslashes($k)] = $v; 
       $process[] = &$process[$key][stripslashes($k)]; 
      } else { 
       $process[$key][stripslashes($k)] = stripslashes($v); 
      } 
     } 
    } 
    unset($process); 
} 

No funciona allí, y el código no es tan largo. =)

+0

Está usando 5.1.0, por lo que no hay espacios de nombres. Todavía puede * intentar * sin embargo. Lanzará un error seguro :) – Gordon

+0

Lo he hecho, trabajando en un proyecto en mi servidor local corriendo PHP 5.3.0, cargándolo a un servidor en vivo ejecutando PHP 5.2.1. Dolores de cabeza, dolores de cabeza –

+0

@Gordon: Oh, no presté atención a eso. Mi error. –

0

Es imposible sin runkit_function_remove. Runkit es la extensión destinada a hacer cosas como esta.

¿Estás seguro de que la función vive una vez completado el bloque si-? Hubiera pensado que si se definiera dentro del bloque if, sería inaccesible después.

+0

Estabas equivocado. 'if' declaraciones no tienen su propio alcance. –

+0

Las funciones no funcionan como variables. Una vez que están definidos, no 'salen del alcance' y están disponibles para toda la aplicación, sin importar dónde estén definidos/declarados. –

0

Estoy de acuerdo con Alix. Sin embargo, puede evitar que se llame a la función desde cualquier otro sitio deshaciéndose de la función. Reescribe la función recursiva como un bucle iterativo. Tendrá la ventaja adicional de reducir el uso de memoria.

ACTUALIZACIÓN: con su ejemplo de código, no estoy seguro de por qué siente la necesidad de evitar que se vuelva a llamar a esta función. Simplemente formatea algunas cadenas en una matriz de forma recursiva ... de nuevo, puedes hacer esto iterativamente y evitar tener una función en primer lugar. De lo contrario, simplemente déjalo allí y no lo vuelvas a llamar.

+0

Y código duplicado aquí y allá –

+1

¿En una función que aparentemente solo se está usando en una ubicación? No lo sé con certeza, pero de la pregunta seguramente parece que la función solo existe para usar la recursión. –

+0

Lo puede estar haciendo por las razones equivocadas, pero definitivamente es correcto dividir el código en muchas funciones, incluso si solo se usan una vez. –

1

No. Pero la eliminación de una definición de función es tonta.
O bien está definiendo la función de manera diferente en un bloque else y necesita la definición para cambiar en función del estado del programa, haciendo que su proyecto sea más y más imposible de depurar, o codifique que las llamadas se bloqueen y se quemen si no funciona sucede que se define en el tiempo de ejecución.

Usted debe poner esta función en una clase:

class foo { 

    public function bar() { 

     if(/* some condition */) { 
      $this->baz(); 
     } else { 
      $this->bazzer(); 
     } 

    } 

    private function baz() { 

     /* if the if condition was met */ 

    } 

    private function bazzer() { 

     /* if the if condition failed */ 

    } 

} 

o, si sólo desea que el estado probó una vez,

class foo { 

    private $bar_function = NULL; 

    public function __construct() { 

     if(/* some condition */) { 
      $this->bar_function = baz; 
     } else { 
      $this->bar_function = bazzer; 
     } 

    } 

    public function bar() { 

     $this->$bar_function(); 

    } 
     ... 

No sé lo que está tratando de hacer o por qué desea eliminar una definición de función, pero con suerte esto puede ayudarlo a hacerlo de una manera más limpia.

+1

+1, usa una clase y hazlo privado – Paolo

+0

OP Editado agregó explicación de lo que estoy haciendo exactamente ... – AlexV

+0

Todavía podrías usar OOP para esto, como una clase Request que obtiene las variables POST, GET, etc. y opcionalmente usa stripslashes en ellos. La función stripslashes_deep podría ser un método privado que el resto de la aplicación no usa y no conoce. –

1

también veo muy pocas razones para dejar que una función "en vivo" o "no vive" dependiendo de una condición, sino para responder a la pregunta, que es una especie de un posible uso de funciones anónimas. @Gordon ya describió cómo se hace. A partir de PHP 5.3.0, también puede usar funciones anónimas de la siguiente manera. (No hay diferencia funcional para el enfoque create_function().)

if (function_exists('get_magic_quotes_gpc') && @get_magic_quotes_gpc()) 
{ 
    $stripslashes_deep = function($value) 
    { 
     return is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value); 
    } 

    $_POST = array_map($stripslashes_deep, $_POST); 
    $_GET = array_map($stripslashes_deep, $_GET); 
    $_COOKIE = array_map($stripslashes_deep, $_COOKIE); 
    $_REQUEST = array_map($stripslashes_deep, $_REQUEST); 

    unset ($stripslashes_deep); 
} 
+0

¿Funcionará 'array_map ('stripslashes_deep', $ value)'? De todos modos, para PHP 5.3+ hay una solución más elegante: ver mi respuesta. –

+0

Sí, funcionará (probado). Su solución es furtiva, ¡bien hecha! :) –

+0

¡Gracias! No soy un gran admirador de las funciones de lambda, pero aún así es bueno saberlo. –

0

Puede haber otra solución para la sustitución de las funciones cambiando el uso de ellos como esto;

function function1(){ 
echo "1"; 
} 

function function2(){ 
echo "2"; 
} 

if(FUNCTION_CHOOSER_CONDITION) $the_function = "function2"; 
else $the_function="function1"; 
$the_function(); // displays 2 if condition is TRUE; 

Tal vez esto no para usted en esta situación, ya que querían destruir la función pero que, aunque este es lugar adecuado para hablar de sustitución de funciones.

3

definición de la función inicial se parece a:

// includes/std_functions.php 
if (! function_exists('the_function')) { 
    function the_function() { 
    global $thefunction; 
    return call_user_func_array($thefunction, func_get_args()); 
    } 
    $GLOBALS['thefunction'] = function() { 
    echo 'foo'; 
    }; 
} 

si usted tiene una condición de prueba que le permite reescribir código:

// somewhere in your code 
if (<replacethefunctioncondition>) { 
    $GLOBALS['thefunction'] = function() { 
    echo 'bar'; 
    }; 
} 

si se sobrecarga en otro incluyen que se cargará antes o después del archivo original:

// includes/custom_functions.php 
if (! function_exists('the_function')) { 
    function the_function() { 
    global $thefunction; 
    return call_user_func_array($thefunction, func_get_args()); 
    } 
} 
$GLOBALS['thefunction'] = function() { 
    echo 'bar'; 
}; 
5

A partir de PHP 5.3 puede utilizar un año función nymous:

$anonymous_function = function($value){ 
    // do stuff 
}; 

llamada así:

$returned_value = $anonymous_function('some parameter'); 

Para eliminar la función, simplemente desactivar la variable:

unset($anonymous_function); 

Aquí está un ejemplo de cómo poner en práctica su función:

$stripslashes_deep = function (&$object){ 
    global $stripslashes_deep; 
    if(is_array($object)) 
    foreach($object as &$value){ 
     if(is_array($value)) 
     $stripslashes_deep($value); 
     else 
     $value = stripslashes($value); 
    } 
}; 

funciones anónimas no tienen nombre. Por lo tanto, no puede usar array_map, ya que solo tomará el nombre de una función como parámetro.

funciones anónimas tiene el alcance variable. Entonces, debe declarar la variable que contiene la función como global, para alcanzarla desde una función recursiva.

Desafortunadamente, si se define una función regular dentro de la función anónima, que será disponible a nivel mundial, incluso después de desarmar la variable. (Realmente no veo el beneficio de eso. Espero que sea un error que se corrija más tarde :-)

+0

[No funcionaría; en primer lugar, falta un punto y coma y, en segundo lugar, no hay ninguna función llamada 'stripslashes_deep'] (https://eval.in/521784). – h2ooooooo

+1

Creo que te estás perdiendo el punto aquí :) pero tienes razón sobre el punto y coma. Gracias. –

Cuestiones relacionadas