2010-01-22 16 views
19

So che questa domanda sembra hacky e strano, ma c'è un modo per rimuovere una funzione in fase di esecuzione in PHP?Rimozione di una funzione in fase di esecuzione in PHP

Ho una funzione ricorsiva dichiarata in un blocco "se" e voglio che quella funzione sia "valida" solo in quel blocco "se". Non voglio che questa funzione venga chiamata al di fuori di questo blocco.

ho scoperto runkit_function_remove ma runkit non è abilitato sul mio host web. C'è un altro modo per farlo?

BTW Sostengo solo PHP 5.1.0.

Edit: sapevo che la mia domanda era hacky, ma qui è la cosa esatta che voglio fare:

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

Dal momento che "stripslashes_deep" sarà solo vivo quando la magia citazioni sono ON, volevo liberatene quando ho finito. Non voglio che le persone facciano affidamento su una funzione che non è sempre . Spero sia più chiaro ora. Anche suggerimenti di soluzioni non hacky sono ben accetti!

+3

Qualsiasi motivo per cui non puoi ** semplicemente non chiamarlo **? –

+0

Non chiamare cosa? – AlexV

+2

Stai attento! Le chiavi della matrice sono anche tagliate da virgolette. –

risposta

18

Dal PHP Manual on Functions:

Tutte le funzioni e le classi PHP, hanno visibilità globale - possono essere chiamate dall'esterno di una funzione anche se sono definite all'interno e viceversa. [...] PHP non supporta l'overloading delle funzioni, né è possibile annullare la definizione o ridefinire le funzioni dichiarate in precedenza.

L'eccezione è tramite runkit. Tuttavia, è possibile definire la funzione come anonymous function e unset dopo averla eseguita, ad es.

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

Alcuni commentors correttamente sottolineato (ma non è un problema più in PHP al giorno d'oggi), non si può chiamare una funzione anonima al suo interno. Utilizzando array_walk_recursive è possibile aggirare questa limitazione. Personalmente, vorrei solo creare una funzione regolare e non preoccuparmi di eliminarlo. Non farà male a nessuno. Basta dare un nome corretto, come stripslashes_gpc_callback.

Nota: modificato e condensato dopo i commenti

+0

È una soluzione "bizzarra", ma mi piace. Se l'OP insiste sull'uso di una funzione, questo è il modo per farlo. –

+0

È possibile eseguire una funzione anonima ricorsiva? – AlexV

+0

Buon punto.Non riesco a pensare a un modo per farlo funzionare con la ricorsione (senza sostanzialmente tornare al codice che hai già). In tal caso, basta ascoltare le sue (e le mie) modifiche e non preoccuparti di rimuovere la funzione. –

3

Risposta semplice: no.

Tuttavia, si può provare a posizionare la funzione all'interno di uno spazio dei nomi, una classe o anche all'interno di un'altra funzione - ma penso che non è quello che stai cercando.

Un altra opzione che avete è quella di utilizzare debug_backtrace() all'interno di detta funzione per controllare quale file/linea/ecc ... sta chiamando - è hackish lo so, ma lo è anche runkit_function_remove().


Edit - Peccato non si esegue PHP 5.3+, altrimenti si può solo fare:

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

Per le vecchie versioni di 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); 
} 

Nessuna funzione lì, e il codice non è così lungo. =)

+0

Sta usando 5.1.0, quindi nessun namespace. Può ancora * provare * però. Avrò sicuramente un errore :) – Gordon

+0

L'ho fatto, lavorando su un progetto sul mio server locale con PHP 5.3.0, caricandolo su un server live con PHP 5.2.1. Mal di testa, mal di testa. –

+0

@Gordon: Oh, non ho prestato attenzione a questo. Errore mio. –

0

E 'impossibile senza runkit_function_remove. Runkit è l'estensione pensata per fare cose come questa.

Sei sicuro che la funzione sia attiva dopo il completamento del blocco if? Avrei pensato che se fosse stato definito all'interno del blocco if, sarebbe diventato inaccessibile in seguito.

+0

Ti sei sbagliato. le dichiarazioni 'if' non hanno il loro scopo. –

+0

Le funzioni non funzionano come variabili. Una volta definiti, non "escono dall'ambito" e sono disponibili per l'intera applicazione, indipendentemente da dove sono definiti/dichiarati. –

0

Sono d'accordo con Alix. Tuttavia, è possibile evitare che la funzione venga richiamata da qualsiasi altra parte eliminando la funzione. Riscrive la funzione ricorsiva come un loop iterativo. Avrai il vantaggio di ridurre l'utilizzo della memoria.

AGGIORNAMENTO: con il proprio esempio di codice, non sono sicuro del motivo per cui si avverte la necessità di impedire che questa funzione venga richiamata di nuovo. Formatta semplicemente alcune stringhe in un array in modo ricorsivo ... di nuovo, è possibile farlo in modo iterativo ed evitare di avere una funzione in primo luogo. Altrimenti, lascialo lì e non chiamarlo più.

+0

E codice duplicato hither e yon –

+1

In una funzione apparentemente utilizzata solo in una posizione? Non lo so per certo, ma dalla domanda suona sicuramente come la funzione esiste solo per usare la ricorsione. –

+0

Potrebbe farlo per le ragioni sbagliate, ma è sicuramente giusto rompere il codice in molte funzioni, anche se vengono utilizzate solo una volta. –

1

No. Ma la rimozione di una definizione di funzione è sciocco.
O si sta definendo la funzione in modo diverso in un blocco else e si ha bisogno che la definizione cambi in base allo stato del programma, rendendo effettivamente il progetto sempre più vicino impossibile da eseguire il debug o il codice che chiama quella funzione si bloccherà e brucerà se non lo avesse 'capita di essere definito in fase di runtime.

Si dovrebbe mettere questa funzione in una classe:

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, se si desidera solo la condizione testato una volta,

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

    } 
     ... 

Non so che cosa si sta cercando di fare o perché vuoi rimuovere una definizione di funzione, ma spero che questo possa aiutarti a farlo in modo più pulito.

+1

+1, usa una classe e rendila privata – Paolo

+0

Modificato OP aggiunto spiegazione di quello che sto facendo esattamente ... – AlexV

+0

Puoi ancora usare OOP per questo, come una classe Request che ottiene le variabili POST, GET, etc e facoltativamente usa strisce su di loro. La funzione stripslashes_deep potrebbe essere un metodo privato che il resto dell'applicazione non utilizza e non conosce. –

1

Anche io vedo poche ragioni per lasciare una funzione "live" o "non live" a seconda di una condizione, ma per rispondere alla domanda, è possibile utilizzare le funzioni anonime. @Gordon ha già delineato come è fatto. A partire da PHP 5.3.0, puoi anche utilizzare le funzioni anonime come segue. (Non v'è alcuna differenza funzionale all'approccio 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

Il 'array_map ('stripslashes_deep', $ valore)' funzionerà ?! Ad ogni modo, per PHP 5.3+ c'è una soluzione più elegante - vedi la mia risposta. –

+0

Sì, funzionerà (testato). La tua soluzione è subdola, ben fatta! :) –

+0

Grazie! Non sono un grande fan delle funzioni lambda ma è bello saperlo comunque. –

0

Ci può essere un'altra soluzione per sostituire funzioni cambiando il loro utilizzo come questo;

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; 

Forse questo non è per voi in questa situazione, come si voleva distruggere la funzione ma io anche se questo è il posto giusto per parlare di sostituzione di funzioni.

3

definizione di funzione iniziale assomiglia:

// 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'; 
    }; 
} 

se si dispone di una condizione di test che permette di riscrivere il codice:

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

se sovramodulate in un altro comprendono che verrà caricata prima o dopo il file originale:

// 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 partire da PHP 5.3 è possibile utilizzare un ano Funzione nymous:

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

chiamare in questo modo:

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

Per eliminare la funzione, basta eliminare la variabile:

unset($anonymous_function); 

Ecco un esempio di come implementare la funzione:

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

funzioni anonime non ha nome. Quindi non è possibile utilizzare array_map, in quanto prenderà solo un nome di funzione come parametro.

funzioni anonime ha lo scope variabile. Quindi devi dichiarare la variabile contenente la funzione come globale, per raggiungerla dall'interno di una funzione ricorsiva.

Sfortunatamente se si definisce una funzione regolare all'interno della funzione anonima, sarà globalmente disponibile, anche dopo aver disinserito la variabile. (Non ne vedo davvero il beneficio. Spero che sia un errore da correggere in seguito :-)

+0

[Non funziona: prima di tutto ti manca un punto e virgola e in secondo luogo non esiste una funzione chiamata 'stripslashes_deep'] (https://eval.in/521784). – h2ooooooo

+1

Penso che manchi il punto qui :) ma hai ragione riguardo al punto e virgola. Grazie. –

Problemi correlati