
Программистам 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 заботиться о том, чтобы класс был подключен а переменная была видна больше нет необходимости.


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