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