Техника синлетонов на php

Программистам php, приходится мириться с тем, что переменная объявленная в любом месте скрипта, не видна ни в одной из функций или методов.

Конечно, есть  ключевое слово global. Но вписывать туда  все используемые переменные очень проблематично, и захламляет код программы.

Поясню на примере:

Пусть есть класс db - обертка над стандартным mysql_query. И класс read_books, который может увеличивать количество просмотров определенной кники по его id.

В большинстве случаев используют такую конструкцию:

<?php 
class read_books{
	function __construct(){
		$this->db =  new db();
		$this->db->connect();
	}
	function f($id){
		$this->db->query('update books set hits=hits+1 where id='.$id);
	}
}
$rd = new read_books();
$rd->f(122);

Из недостатков: для каждого экземпляра read_books будет создаваться отдельное подключение к бд. Понятно, что для работы скрипта, достаточно лишь одного подключения. Поэтому, многие пишут так:

<?php 
$db =  new db();
$db->connect();
class read_books{
	function __construct(){
		global $db;
		$this->db =  $db;
	}
	function f($id){
		$this->db->query('update books set hits=hits+1 where id='.$id);
	}
	function f1($id){
		// либо используем $db напрямую
		global $db;
		$db->query('update books set hits=hits+1 where id='.$id);
	}
}
$rd = new read_books();
$rd->f(122);
$rd->f1(123);

Минусы я озвучил выше. По мере разрастания программы, следить за доступностью такой глобальной переменной, станет все сложнее и сложнее, а иногда и просто невозможно. 

В этой статье я расскажу про технику Singleton'ов, с которой я познакомился  благодаря Хабру.

Итак, шаблон проектирования Singleton, это такая структура классов, по которой у одного класса может быть только один экземпляр. Это оправданно для большинства служебных классов: работа с БД, работы с шаблонизатором, роутер и т.д. 

При этом, сам экземпляр класса не создается явно через ключевое слово new, а доступен прямо из объявления класса, т.е. глобально. Непонятно? Сейчас покажу, как это на самом деле просто.

<?php
abstract class Singleton{
 // в $_aInstances будут хранится все 
 // экзмепляры всех классов наследующих класс Singleton
 private static $_aInstances = array();
 public static function getInstance() {
  $sClassName = get_called_class(); // название класса экземпляр которого мы запросили
  if( class_exists($sClassName) ){
   if( !isset( self::$_aInstances[ $sClassName ] ) )
    // если экземпляр класса еще не был создан, создаем его 
    self::$_aInstances[ $sClassName ] = new $sClassName();
   // возвращаем один экземпляр
   return self::$_aInstances[ $sClassName ]; 
  }
  return 0;
 }
 // более удобный вызов метода getInstance
 public static function gI() {
  return self::getInstance();
 }
 // так как нам нужен лишь один экземпляр любого класса,
 // то копировать объекты нам не потребуется
 final private function __clone(){}
 private function __construct(){}
}

 теперь при создании класса наследуем Singleton

<?php
class db extends Singleton{
	private $connid = 0;
	function query($sql){
		// запрос
		return mysql_query(Sql,$this->connid);
	}
	function connect(){
		// подключение
		$this->connid = @mysql_connect('127.0.0.1', 'root', '') ;
		mysql_select_db('books', $this->connid);
	}
}
db:gi()->connet();// правда удобно?!

и в нашем классе тоже доступен db:gi()

<?php 
class read_books{
	function f($id){
		db::gi()->query('update books set hits=hits+1 where id='.$id);
	}
}
$rd = new read_books();
$rd->f(122);

И никаких проблем с видимостью. Для всех read_books будет создан всего один экземпляр db с одним подключением.  В купе c техникой автозагрузки необходимых файлов на php заботиться о том, чтобы класс был подключен а переменная была видна больше нет необходимости.

Рассказать друзьям

Добавить комментарий


Защитный код
Обновить

Комментарии   

0
Пхпехер
# Пхпехер 02.08.2014 01:58
Fatal error: Uncaught exception 'Except' with message 'Class App no exist!' in V:\home\test1.ru\www\ideal\classes\Singleton.php:1 3 Stack trace: #0 V:\home\test1.ru\www\ideal\classes\Singleton.php(1 6): Singleton::getInstance('indexController') #1 V:\home\test1.ru\www\ideal\classes\App.php(5): Singleton::gI('indexController') #2 V:\home\test1.ru\www\main.php(6): App->start() #3 {main} thrown in V:\home\test1.ru\www\ideal\classes\Singleton.php on line 13



Вуаля. Если пишите поучительное что то... убедитесь что работает.