Indice del forum Olimpo Informatico
I Forum di Zeus News
Leggi la newsletter gratuita - Attiva il Menu compatto
 
 FAQFAQ   CercaCerca   Lista utentiLista utenti   GruppiGruppi   RegistratiRegistrati 
 ProfiloProfilo   Messaggi privatiMessaggi privati   Log inLog in 

    Newsletter RSS Facebook Twitter Contatti Ricerca
Singleton con php
Nuovo argomento   Rispondi    Indice del forum -> Linguaggi per Internet
Precedente :: Successivo  
Autore Messaggio
freemind
Supervisor sezione Programmazione
Supervisor sezione Programmazione


Registrato: 04/04/07 21:28
Messaggi: 4643
Residenza: Internet

MessaggioInviato: 06 Lug 2008 18:23    Oggetto: Singleton con php Rispondi

Salve popolo del forum,
vorrei scambiare due parole con voi, in php, sul concetto di singleton.
Al momento vorrei solo trattare gli aspetti pratici della cosa senza dissertare a lungo su concetti teorici, che comunque vengono applicati nell'ingegneria del software.
La definizione di singleton è semplice: "Un singleton è una classe che prevede una sola istanza di se stessa."
Praticamente parliamo di singleton quando c'è un meccanismo che fa si che se si istanzia una classe, i tentativi successivi al primo ritornano un riferimento (o un puntatore) alla prima istanza.
Esiste un design pattern basato sui singleton ma qui, lascierei perdere.
Ci sono situazioni in cui il singleton è fondamentale mentre in altre aiuta a mantenere il progetto pulito e in oltre impedisce sprechi inutili di memoria.
Tramite i singleton possiano evitare di creare var globali che di fatto sporcano il nostro progetto.
Un caso che mi viene in mente per l'uso di un singleton è il logger.
Mostrerò qui come scrivere una semplice classe Logger che guarda caso servirà a loggare ciò che avviene durante l'esecuzione dello script.

Il contesto è semplice: avremo 3 classi: il logger, e altre due i cui costruttori faranno uso del logger per memorizzare la data e l'ora di istanziatura (non so se questa parola esiste in italiano) delle classi rispettive.

Di seguito riporto la semplice classe Logger già pronta come singleton e poi farò qualche commento.
Codice:

<?php
   final class Logger
   {
   // Riferimento all'istanza della classe
      private static $instance=null;
      
      private $fileName='log.log';
      
   // (1) Costruttore protetto
      private function __construct()
      {
         
      }
      
   // (2) definizione di __clone()
      private function __clone()
      {
         
      }
      
   // (3) metodo statico che gestisce l'istanziatura della classe
      static public function getInstance()
      {
         if (self::$instance==null)
         {
            self::$instance=new self();
         }
         
         return self::$instance;
      }
      
   /**
    * Metodo che scrive nel file definito in $this->$fileName.
    * Lancia un'eccezione se non riesce a creare il file di log
    *
    * @param string $msg: messaggio da scrivere nel log
    */
      public function log($msg)
      {
         $f=false;
         
         $f=@fopen($this->fileName,'a');
         
         if ($f===false)
            throw new Exception('Non posso creare il file di log!');
         
         $row=date('d-m-Y H:i:s') . ' --> ' . $msg . "\n";            
         fputs($f,$row);

         fclose($f);
      }
   }
?>

Possiamo notare come prima cosa anomala il costruttore private.
Il motivo è semplice: dobbiamo impedire che la classe venga istanziata nel caso avvenisse una chiamata del tipo
Codice:

$l=new Logger();

Dato che il costruttore è private non possiamo raggiungerlo dall'esterno della classe quindi l'allocazione fallisce.
Il ritorno dell'istanza viene demandato al metodo pubblico statico getInstance(); se non esiste un'istanza della classe, la crea e la ritorna altrimenti ritorna l'istanza già predsente. Il metodo è statico perchè dobbiamo poterlo usare senza aver istanziato tramite "new".
La proprietà private $instance rappresenta l'istanza della classe stessa.
Abbiamo il metodo pubblico log che serve a scrivere nel file di log il messaggio $msg.
Ho definito il magic method __clone() private affinchè non faccia nulla: questo fa si che in caso venga usata la funzione clone(...) per clonare un'oggetto, questa fallisca.
La classe è "final" per evitare che venga ereditata.
Abbiamo un singleton a tutti gli effetti e ora vediamo come usarlo.
Creiamo due classi stupide stupide:
Codice:

<?
   class Uno
   {
      public function Uno()
      {
         $l=Logger::getInstance();
         try
         {
            $l->log('Classe Uno istanziata!');
            print 'Loggata classe Uno<br>';
         }   
         catch(Exception $e)
         {
            print $e->getMessage();
         }
      }
      
      // altri metodi e altre proprietà
   }
   
   class Due
   {
      public function Due()
      {
         $l=Logger::getInstance();
         try
         {
            $l->log('Classe Due istanziata!');
            print 'Loggata classe Due<br>';
         }   
         catch(Exception $e)
         {
            print $e->getMessage();
         }
      }
      
      // altri metodi e altre proprietà
   }
?>

Come potete vedere queste due classi hanno solo un costruttore il quale genera l'istanza di Logger e scrive nel log la data di creazione dell'oggetto.
Per provare fate due chiamate del tipo:
Codice:

<?
   $u=new Uno();
   $d=new Due();
?>

Potete provare a fare esperimenti come:
Codice:

<?
   $l=new Logger();
?>

e otterrete un fallimento. Provate anche con:
Codice:

<?
   $l=Logger::getInstance();
   $l2=Logger::getInstance();
   var_dump($l);
   print '<br>';
   var_dump($l2);
?>

e noterete che le due istanze di fatto sono la stessa.
Per verificare di non riuscire a clonare il logger scrivete:
Codice:

<?
   $l=Logger::getInstance();
   $l2=clone($l);
?>

e otterrete un bel niente.
Così come con
Codice:

<?
   $l=Logger::getInstance();
   $l2=$l;
?>

Sarebbe bello ricevere qui i vostri commenti su questa cosa, magari con idee e migliorie sia a livello del codice proposto che della trattazione.
Vi lascio con una richiestina:
Qualcuno vorrebbe provare a creare una classe che renda possibile l'utilizzo in singleton di una classe generica non progettata per esserlo?

Saluti
freemind
Top
Profilo Invia messaggio privato
Mostra prima i messaggi di:   
Nuovo argomento   Rispondi    Indice del forum -> Linguaggi per Internet Tutti i fusi orari sono GMT + 2 ore
Pagina 1 di 1

 
Vai a:  
Non puoi inserire nuovi argomenti
Non puoi rispondere a nessun argomento
Non puoi modificare i tuoi messaggi
Non puoi cancellare i tuoi messaggi
Non puoi votare nei sondaggi