PHP

Как получить доступ к экземпляру класса на 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 заботиться о том, чтобы класс был подключен а переменная была видна больше нет необходимости.
Теги:
singleton, шаблоны, паттерн, abstract class, глобальные переменные
Добавлено: 20 Апреля 2018 19:31:27 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...