Singleton
In php, il Singleton è il nome di un pattern di linguaggio, che permette di creare un oggetto solo una volta.
La sua forma più semplice prevede:
- una proprietà statica privata che conterrà l’istanza dell’oggetto passata poi dal metodo
- un costruttore privato che creerà l’oggetto
- un metodo statico pubblico getinstance che restituirà l’istanza della classe
Praticamente viene creato l’oggetto della classe direttamente all’interno della classe.
class Singleton { private static $Istanza; private function __construct() {} public static function getIstance() { if (self::$Istanza === null) { $classe = __CLASS__ ; self::$istanza = new $classe ; } return self::$istanza; } }
Un caso utile in cui utilizzare singleton è quando si deve effettuare una connessione al database e si vuole avere una sola istanza per tutto il codice senza dover creare numerosi oggetti per ogni connessione.
Ecco un esempio utilizzando la classe PDO,
iniziamo però creando metodo statico pubblico getIstance():
public static function getInstance(array $options) { }
In questo caso il metodo getIstance() riceve un array di opzioni che corrispondono ai parametri del collegamento al database.
Ora creiamo il costruttore:
protected function __construct(array $options) { }
anche il costruttore riceverà un array di opzioni che serviranno a costruire la connessione, ma prima definiamo una proprietà protetta di connessione:
protected $conn ;
Supponendo che ci vengono passate tutte le opzioni della connessione, magari da un altro file di configurazione, andiamo a creare la connessione nel costruttore:
protected function __construct(array $options) { $this->conn = new \PDO($options['dsn'],$options['user'],$options['password'],$options['pdooptions'] ); }
Da notare l’uso del namespace globale \PDO() .
Adesso vediamo come creare una sola istanza della classe per la connessione, che è il più importante vantaggio del pattern singleton, intanto creiamo un’altra proprietà protetta statica per l’istanza unica, per questo la creiamo statica:
protected static $instance;
ora andiamo ad impostare l’istanza della classe nel metodo getIstance(), controllando che non sia già stata creata:
public static function getInstance(array $options) { if(!static::$instance){ static::$instance = new static($options); } return static::$instance; }
Se $istance è null, allora mi crei un oggetto con new nome della classe, oppure new static che crea un’istanza della classe stessa, la quale farà partire il costruttore che a sua volta stanzierà l’oggetto PDO passando all’oggetto appena creato le opzioni della connessione ($options).
Se l’stanza esiste già in $istance la restituisce con return static::$istance.
Aggiungiamo un metodo pubblico per accedere alla connessione:
public function getConn() { return $this->conn; }
Ritornando $instance avremo accesso ai dati di connessione al database e con il costruttore protected potremmo anche eventualmente estendere la classe in modo che quella figlia possa implementare i metodi e aggiungere eventuali altre funzionalità.
Ecco il codice della classe completo in un namespace App\DB :
namespace App\DB; class DBPDO { protected $conn ; protected static $instance; public static function getInstance(array $options) { if(!static::$instance){ static::$instance = new static($options); } return static::$instance; } protected function __construct(array $options) { $this->conn = new \PDO($options['dsn'],$options['user'],$options['password'],$options['pdooptions'] ); } public function getConn() { return $this->conn; } }
ora nel file che lancerà la connessione includiamo la classe DBPDO e il file di configurazione che conterrà i dati di collegamento al database :
require_once __DIR__.'/app/DB/DBPDO.php'; $data = require 'config/database.php';
passiamo i dati caricati in $data al metodo getInstance()
$pdoConn = App\DB\DBPDO::getInstance($data);
ora ho la connessione creata dal costruttore con PDO, lancio la connessione:
$conn = $pdoConn->getConn();
L’oggetto PDO ha un metodo che si chiama query che si può usare se non abbiamo nessun parametro o non riceviamo i dati da un form, altrimenti bisogna usare i PDOStatement con PDO::prepare che prepara la query proteggendoci da eventuali SQL injection.
Nel nostro esempio facciamo una select secca senza parametri, usando PDO->query
$stm = $conn->query('select * from tabella', PDO::FETCH_OBJ);
PDO::FETCH_OBJ restituisce un oggetto contenente i dati del db.
Posso anche usare anche PDO::FETCH_ASSOC per restituire un array coi dati o altri metodi a seconda dell’esigenza.
Cicliamo ora la query per stamparne il risultato coi dati ottenuti dal db:
if($stm){ foreach ($stm->fetchAll() as $row){ print_r($row); } }
Lo statement ha diversi metodi che si possono usare per restituire i dati, in questo caso abbiamo usato $stm->fetchAll() che li restituisce tutti, da non usare in presenza di molti dati perchè consumerebbe molte risorse.