Application Controller con Reflection in PHP

Il pattern architetturale Application Controller con Reflection in PHP per sistema software con architettura a livelli.

In questo periodo sto sviluppando un sistema software in PHP, ho scelto un ciclo di sviluppo incrementale e una architettura a livelli. Come sempre un obiettivo importante in termini di qualità è avere una manutenibilità soddisfacente, per far ciò occorre ridurre per quanto possibile la dipendenza tra le componenti.
L’utilizzo dei pattern architetturali è fondamentale, ho pensato quindi di usare il già collaudato Application Controller.

Progettazione Application Controller con Reflection in PHP.
Vediamo direttamente i diagrammi UML che sono sempre esplicativi.
Diagramma UML application controller con reflection


E’ mostrato il diagramma per il package presentation che collabora con il business.
Possiamo notare:

  • La classe LoginAS è una classe di servizio, come questa ce ne sono molte altre, ognuna astrae un funzionalità. Tutte le classi di servizio estendono la Service;
  • La classe Service è la root della gerarchia di business, essa fornisce un interfaccia al livello superiore presentation;
  • La classe RequestController riceve dal livello superiore una stringa che identifica la funzionalità da eseguire, essa ha una struttura dati interna(*) (un dizionario, la variabile $matrix) così ottiene la classe di servizio associata a quella funzionalità.

(*): in altri progetti che richiedono una più alta manutenibilità, si potrebbe scegliere di utilizzare un’altra modalità per immagazzinare le corrispondenze nome funzionalità->classe di servizio (in adisystem per esempio avevo usato un file persistente in XML, in questo modo addirittura si può evitare di entrare nel codice del RequestController)

Ecco i passi che la struttura esegue per chiamare una funzionalità

  1. Il cliente chiama il metodo handleRequest di RequestController passando in input il nome della funzionalità (ad esempio “login”) e l’eventuale input;
  2. Il RequestController dal nome di funzionalità deduce la classe di servizio che implementa quella funzionalità;
  3. Il RequestController istanzia la classe di servizio passandole in input il nome di funzionalità;
  4. La classe di servizio dal nome di funzionalità deduce il proprio metodo da evocare e lo passa in output al RequestController;
  5. Il RequestController evoca il metodo ricevuto con l’input

Implementazione Application Controller con Reflection in PHP.
L’implementazione della Reflection in PHP è molto più semplice di quella in Java (che ho implementato per il progetto AdiSystem), merito della minore tipizzazione dei dati e della maggiore dinamicità del PHP. Ci si accorge di questo da subito, dando una rapida lettura all’esempio fornito nella documentazione PHP.

Classe RequestController: gestisce la richiesta proveniente dal livello più alto.
Il cliente chiama il metodo handleRequest con una stringa che identifica la funzionalità e l’input.

class RequestController{
 
    /**Matrice che associa ad un nome di funzionalità un'istanza di classe*/
    private $matrix;
 
    /**
     * Inizializzazione della matrice
    */
    function __construct(){
        $this->matrix = array(
            "nomeFunzionalita" => "Classe_di_servizio",
        );
    }
 
   /**
     * Dalla $matrix ottiene il nome della classe dalla funzionalita'.
     * Ottiene l'istanza della classe mediante ReflectionClass
    */
    function handleRequest($nomeFunz, $input=null){
 
        //ottiene il nome della classe che gestisce la funzionalita' richiesta 
        //dall'utente
        $nomeClasse = $this->matrix[$nomeFunz];
 
        $reflectionClass = new ReflectionClass($nomeClasse);
 
        //ora ottengo una istanza della classe (di cui possiedo solo il nome!)
        $class = $reflectionClass->newInstance();
 
        //la classe istanziata deve estendere Service, quindi ha il metodo execute
        //questo metodo ritorna il metodo in reflection da eseguire
        //(classe ReflectionMethod)
        $method = $class->execute($nomeFunz);
 
        return $method->invoke($class, $input);
    }
}

Classe Service: root della gerarchia di classi di servizio del sistema.

 
class Service{
 
    protected $matrix;
 
    /**
     * Questa funzione sara' ereditata da ogni classe di servizio.
     * Deve utilizzare la REFLECTION. Chiamare un metodo
     * conoscendo solo il suo nome senza avere l'istanza della classe.
    */
    function execute($nomeFunz){
 
        //ottengo il nome della classe attualmente in esecuzione che estende questa
        $nomeClass = get_class($this);
 
	//ottengo il nome del metodo associato alla funzionalita' richiesta
        $nomeMethod = $this->matrix[$nomeFunz];
 
        //ottengo il metodo reflection che puo' essere successivamente evocato passando
	//gli input che esso richiede
        $reflectionMethod = new ReflectionMethod($nomeClass, $nomeMethod);
 
        return $reflectionMethod;
    }
}