Visualizzazione dei risultati da 1 a 7 su 7
  1. #1

    Inizializzare classi dinamicamente con numero di parametri variabile

    Hola a todos,

    volevo eliminare un eval che attualmente utilizzo per instanziare classi (componenti del framework). Il problema è che il numero di parametri che passo alle classi (componenti) varia da classe a classe (ovviamente direi)

    Il codice con eval che uso è qualcosa tipo:
    codice:
    $parametersToEvalParts = array();
                
    foreach($Parameters as $key => $value)
    {
        $parametersToEvalParts[] = "\$Parameters[{$key}]";
    }
                
    // Esegue il codice PHP tramite eval ed acquisisce il componente
    eval("\$componentObject = new {$componentName}(" . implode(', ', $parametersToEvalParts) . ");");
    Utilizzo PHP5, quindi evenuali oggetti sono passati di default per riferimento, e quindi questo sistema non mi consuma memoria inutilmente (troppa memoria inutilmente), però comunque un eval cosi rallenta e non permette il caching correttamente del codice ad APC/eAccelerator e simili.

    Sono passato quindi ad usare la reflection (la classe ReflectionClass ed il metodo newInstanceArgs che è più veloce di un buon 50%/60% e consuma quasi la metà della memoria) però comunque la reflection è lenta!

    Il codice con la reflection è
    codice:
    // Instanzia la classe ReflectionClass per gestire l'instanziazione
    // del componente
    $componentObjectRC = new ReflectionClass($componentName);
                
    // Instanzia l'oggetto
    $componentObject = $componentObjectRC->newInstanceArgs($Parameters);
    
    // Libera la memoria
    unset($componentObjectRC);
    Qualche suggerimento per metter su un sistema un pò più veloce lo avete?
    The fastest Redis alternative ... cachegrand! https://github.com/danielealbano/cachegrand

  2. #2
    Ti posto un estratto del metodo dispatchMethod() della classe base Object di CakePHP:
    Codice PHP:
    /**
     * Calls a method on this object with the given parameters. Provides an OO wrapper
     * for call_user_func_array, and improves performance by using straight method calls
     * in most cases.
     *
     * @param string $method  Name of the method to call
     * @param array $params  Parameter list to use when calling $method
     * @return mixed  Returns the result of the method call
     * @access public
     */
        
    function dispatchMethod($method$params = array()) {
            switch (
    count($params)) {
                case 
    0:
                    return 
    $this->{$method}();
                case 
    1:
                    return 
    $this->{$method}($params[0]);
                case 
    2:
                    return 
    $this->{$method}($params[0], $params[1]);
                case 
    3:
                    return 
    $this->{$method}($params[0], $params[1], $params[2]);
                case 
    4:
                    return 
    $this->{$method}($params[0], $params[1], $params[2], $params[3]);
                case 
    5:
                    return 
    $this->{$method}($params[0], $params[1], $params[2], $params[3], $params[4]);
                default:
                    return 
    call_user_func_array(array(&$this$method), $params);
                break;
            }
        } 
    Ovviamente non puoi usare call_user_func_array() per istanziare una nuova classe, ma penso tu possa ottenere un incremento di performance replicando l'idea dello switch() (magari fino ad 10/15 parametri) per poi ripiegare sulla reflection nel caso in cui il numero di parametri non sia stato gestito precedentemente.

  3. #3
    Scusa per il doppio post.

  4. #4
    Anche se un pò contorta, non è niente male l'idea alla base

    Mi sa che fò un misto tra questo e la reflection (che comunque rimane più veloce di eval)
    The fastest Redis alternative ... cachegrand! https://github.com/danielealbano/cachegrand

  5. #5
    Grazie tantissime per il suggerimento, l'ho modificato in qualcosa tipo

    codice:
        if (isset($parameters[4]))          
            $obj = new Bar($parameters[0], $parameters[1], $parameters[2], $parameters[3], $parameters[4]);
    
        else if (isset($parameters[3]))          
            $obj = new Bar($parameters[0], $parameters[1], $parameters[2], $parameters[3]);
    
        else if (isset($parameters[2]))          
            $obj = new Bar($parameters[0], $parameters[1], $parameters[2]);
    
        else if (isset($parameters[1]))          
            $obj = new Bar($parameters[0], $parameters[1]);
    
        else if (isset($parameters[0]))
            $obj = new Bar($parameters[0]);
    facendo cosi l'overhead nell'esecuzione, rispetto allo stesso numero di case, praticamente è la metà!

    codice:
    Eval:
        Time:1.575356
    
    Reflection:
        Time:0.839905
    
    Direct:
        Time:0.314733
    
    Direct using if:
        Time:0.371234
    
    Direct using switch:
        Time:0.456811
    In realtà siccome è il tempo di esecuzione complessivo di 100000 ritengo che vada sufficentemente bene
    The fastest Redis alternative ... cachegrand! https://github.com/danielealbano/cachegrand

  6. #6
    Perchè non utilizzi lo switch?

    Secondo me è più performante, inoltre penso che statisticamente il numero medio dei parametri di inizializzazione delle classi sia molto basso, per cui verificando in ordine il numero dei parametri potresti ottenere un ulteriore miglioramento.

  7. #7
    mi ero dimenticato a cambiare il nome dell'ultimo test che è Direct with switch

    Usando lo switch ho performance leggermente superiori (leggermente perché parliamo sempre di valori microscopici) probabilmente per via del count

    Almeno 10 parametri diretti mi servono perché ci sono un paio di componenti del framework (gestione sessioni e gestione utenti, che essendo altamente customizzabili, prendono in ingresso, rispettivamente, 10 e 8 parametri)
    The fastest Redis alternative ... cachegrand! https://github.com/danielealbano/cachegrand

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.