2011-02-04 26 views
5

Anche se ci sono alcune discussioni su questo problema, ho voluto verificare su alcuni esempi quale sarebbe l'approccio migliore.
Invece di usare soluzioni esistenti ho creato il mio livello di persistenza (come molti altri) Quindi il mio approccio è anche in discussione qui.Php (eval vs call_user_func vs funzioni variabili ...)

Per ogni tabella in db ho una classe di modello con getter e setter appropriati e alcuni metodi obbligatori. Ho anche creato solo una classe DAO generica che gestisce tutti i tipi di oggetti del modello.
Quindi, ad esempio per salvare qualsiasi oggetto del modello, istanzio la classe genericaDAO e il metodo di salvataggio delle chiamate che passo come oggetto. Il problema è che in runtime la classe genericDAO non conosce l'oggetto del modello che riceve e quali metodi (getter e setter) esistono in esso, quindi devo chiamare il metodo obbligatorio della classe del modello che recupera l'elenco di attributi come array di stringhe multiple.
Ad esempio per ogni attributo c'è array (table_column_name, attribute_name, is_string).

Quando chiamo la funzione di risparmio sembra che questo:

public function save(&$VO) { 
$paramArray = $VO->getParamArray();//get array of attributes 
$paramIdArray = $paramArray[0]; //first attribute is always id 
/*create and execute getId() and store value into $void to check if it's save or update*/ 
eval('$voId = $VO->get'.ucfirst($paramIdArray[1]).'();'); 
...

Attualmente sto usando eval per eseguire questi metodi, ma, come è ben noto eval è molto lento.
Sto pensando di cambiare che nel metodo call_user_func
Qualcosa di simile:

$voId = call_user_func(array($VO, 'get'.ucfirst($paramIdArray[1]))); 

Ma anche ci sono altre soluzioni. Posso forse usare qualcosa di simile

$method = 'get'.ucfirst($paramIdArray[1])); 
$voId = $VO->$method(); 
oppure

$method = 'get'.ucfirst($paramIdArray[1])); 
$voId = $VO->{$method}(); 

Quale sarebbe il modo migliore?

risposta

8

Prima di tutto, non è necessario passare dei riferimenti come si sta facendo. Devi provare give this a read per capire come PHP gestisce i riferimenti agli oggetti.

Quindi public function save(&$VO) { dovrebbe diventare public function save($VO) {.

In secondo luogo, non è necessario utilizzare eval (infatti, è preferibile non a causa di velocità, debugabilità, ecc.). Non è possibile tracciare stack di una chiamata eval come se fosse dinamica.

In terzo luogo, call_user_func è praticamente inutile poiché PHP supporta le funzioni variabili dinamiche. Invece di call_user_func(array($obj, $method), $arg1), chiama semplicemente $obj->$foo($arg1). La funzione call_user_func_array è ancora utile poiché supporta argomenti di lunghezza variabile e supporta riferimenti di passaggio.

Quindi, in definitiva, vorrei suggerire questo:

$method = 'get' . ucfirst($paramIdArray[1]); 
$voId = $VO->$method(); 

Nota che non c'è bisogno di chiamare method_exists, dal momento che può essere richiamabile e non esiste a causa di __get sostegno metodo magico ...

+0

Penso che "call_user_func()" sia ancora l'unico modo per chiamare una funzione anonima memorizzata nella variabile oggetto: '$ o- > f = function() {}; 'cercando di fare' $ o-> f() 'risulterà in' $ o non ha un metodo chiamato avvertimento 'f''. – Mchl

+0

@Mchl: '$ c = $ o-> f; $ c(); 'funzionerà. Oppure puoi implementare un metodo magico '__call' per farlo per te. Ma non * devi * usare 'call_user_func'. E questo è il punto di ciò che stavo cercando di dire. Non fa nulla che non puoi fare nella lingua nativa ... Potrebbe essere più facile da fare e leggere, ma non sta facendo nulla di speciale ... – ircmaxell

+0

Ah sì. Ho dimenticato '$ c = $ o-> f; $ c(); ', Hai ragione su questo. – Mchl

2

normalmente userei:

$method = 'get'.ucfirst($attribute); 
if(method_exists($obj, $method){ 
    $obj->$method(); 
} 

Ma a meno che non ci sia una buona ragione vorrei solo restituire una matrice key => value da getParamArray. E operare su questo invece di usare i getter ...

+0

Sì, è probabilmente più veloce se si evita di utilizzare getter ... fino a quando non creano un modificatore di accesso privato :) – Aleksandar