Создание шаблона проектирования Singleton в PHP5 - PullRequest
198 голосов
/ 15 октября 2008

Как создать класс Singleton, используя классы PHP5?

Ответы [ 20 ]

3 голосов
/ 10 августа 2013

Вся эта сложность («поздняя статическая привязка» ... харумф) для меня просто признак неработающей модели объекта / класса в PHP. Если бы объекты класса были объектами первого класса (см. Python), то переменная $ _instance была бы переменной класса instance - членом объекта класса, а не элементом / свойством его экземпляров, а также в отличие от общих потомков. В мире Smalltalk это разница между «переменной класса» и «переменной экземпляра класса».

В PHP мне кажется, что нам нужно принять к сведению руководство о том, что шаблоны являются руководством к написанию кода - возможно, мы подумаем о шаблоне Singleton, но пытаемся написать код, который наследуется от фактического Синглтон "класс выглядит неправильно для PHP (хотя я предполагал, что какая-то предприимчивая душа могла бы создать подходящее ключевое слово SVN).

Я продолжу просто кодировать каждый синглтон отдельно, используя общий шаблон.

Заметьте, что я абсолютно не в курсе дискуссии о злодеях, жизнь слишком коротка.

2 голосов
/ 25 января 2013

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

Вот пример: я решил запустить свой собственный MVC и шаблонизатор, потому что я хотел что-то действительно легкое. Однако данные, которые я хочу отобразить, содержат много специальных математических символов, таких как & ge; и & mu; и что у вас ... Данные хранятся как фактические символы UTF-8 в моей базе данных, а не как предварительно закодированные в формате HTML, потому что мое приложение может предоставлять другие форматы, такие как PDF и CSV в дополнение к HTML. Подходящее место для форматирования для HTML находится внутри шаблона («вид», если хотите), который отвечает за рендеринг этого раздела страницы (фрагмент). Я хочу преобразовать их в соответствующие им объекты HTML, но функция PHP get_html_translation_table () не является супер быстрой. Имеет смысл извлечь данные один раз и сохранить их в виде массива, что сделает их доступными для всех. Вот образец, который я собрал, чтобы проверить скорость. Предположительно, это будет работать независимо от того, были ли другие методы, которые вы используете (после получения экземпляра), статическими или нет.

class EncodeHTMLEntities {

    private static $instance = null;//stores the instance of self
    private $r = null;//array of chars elligalbe for replacement

    private function __clone(){
    }//disable cloning, no reason to clone

    private function __construct()
    {
        $allEntities = get_html_translation_table(HTML_ENTITIES, ENT_NOQUOTES);
        $specialEntities = get_html_translation_table(HTML_SPECIALCHARS, ENT_NOQUOTES);
        $this->r = array_diff($allEntities, $specialEntities);
    }

    public static function replace($string)
    {
        if(!(self::$instance instanceof self) ){
            self::$instance = new self();
        }
        return strtr($string, self::$instance->r);
    }
}
//test one million encodings of a string
$start = microtime(true);
for($x=0; $x<1000000; $x++){
    $dump = EncodeHTMLEntities::replace("Reference method for diagnosis of CDAD, but clinical usefulness limited due to extended turnaround time (≥96 hrs)");
}
$end = microtime(true);
echo "Run time: ".($end-$start)." seconds using singleton\n";
//now repeat the same without using singleton
$start = microtime(true);
for($x=0; $x<1000000; $x++){
    $allEntities = get_html_translation_table(HTML_ENTITIES, ENT_NOQUOTES);
    $specialEntities = get_html_translation_table(HTML_SPECIALCHARS, ENT_NOQUOTES);
    $r = array_diff($allEntities, $specialEntities);
    $dump = strtr("Reference method for diagnosis of CDAD, but clinical usefulness limited due to extended turnaround time (≥96 hrs)", $r);
}
$end = microtime(true);
echo "Run time: ".($end-$start)." seconds without using singleton";

В основном я видел типичные результаты, подобные этому:

php test.php
Run time: 27.842966794968 seconds using singleton
Run time: 237.78191494942 seconds without using singleton

Итак, хотя я, конечно, не эксперт, я не вижу более удобного и надежного способа уменьшить накладные расходы на медленные вызовы для некоторого вида данных, в то же время делая его очень простым (одна строка кода, чтобы делать то, что вы необходимость). Конечно, в моем примере есть только один полезный метод, и поэтому он ничуть не лучше глобальной функции, но как только у вас появятся два метода, вы захотите сгруппировать их, верно? Я далеко от базы?

Кроме того, я предпочитаю примеры, которые на самом деле что-то делают, поскольку иногда трудно визуализировать, когда пример включает в себя такие выражения, как «// сделать что-то полезное здесь», которые я вижу все время при поиске учебников.

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

1 голос
/ 31 января 2017

Я написал давно, думал, чтобы поделиться здесь

class SingletonDesignPattern {

    //just for demo there will be only one instance
    private static $instanceCount =0;

    //create the private instance variable
    private static $myInstance=null;

    //make constructor private so no one create object using new Keyword
    private function  __construct(){}

    //no one clone the object
    private function  __clone(){}

    //avoid serialazation
    public function __wakeup(){}

    //ony one way to create  object
    public static  function  getInstance(){

        if(self::$myInstance==null){
            self::$myInstance=new SingletonDesignPattern();
            self::$instanceCount++;
        }
        return self::$myInstance;
    }

    public static function getInstanceCount(){
        return self::$instanceCount;
    }

}

//now lets play with singleton design pattern

$instance = SingletonDesignPattern::getInstance();
$instance = SingletonDesignPattern::getInstance();
$instance = SingletonDesignPattern::getInstance();
$instance = SingletonDesignPattern::getInstance();

echo "number of instances: ".SingletonDesignPattern::getInstanceCount();
1 голос
/ 17 декабря 2015

Эта статья охватывает тему довольно широко: http://www.phptherightway.com/pages/Design-Patterns.html#singleton

Обратите внимание на следующее:

  • Конструктор __construct() объявлен как protected, чтобы предотвратить создание нового экземпляра вне класса с помощью оператора new.
  • Магический метод __clone() объявлен как private для предотвращения клонирования экземпляра класса с помощью оператора clone.
  • Магический метод __wakeup() объявлен как private для предотвращения десериализации экземпляра класса с помощью глобальной функции. unserialize().
  • Новый экземпляр создается с помощью поздней статической привязки в методе статического создания getInstance() с ключевым словом static. это разрешает создание подкласса class Singleton в примере.
0 голосов
/ 01 февраля 2013

Вот мой пример, который предоставляет возможность вызывать как $ var = new Singleton (), а также создавать 3 переменные, чтобы проверить, создает ли он новый объект:

class Singleton{

    private static $data;

    function __construct(){
        if ($this::$data == null){
            $this->makeSingleton();
        }
        echo "<br/>".$this::$data;
    }

    private function makeSingleton(){
        $this::$data = rand(0, 100);
    }

    public function change($new_val){
        $this::$data = $new_val;
    }

    public function printme(){
        echo "<br/>".$this::$data;
    }

}


$a = new Singleton();
$b = new Singleton();
$c = new Singleton();

$a->change(-2);
$a->printme();
$b->printme();

$d = new Singleton();
$d->printme();
0 голосов
/ 02 января 2016

Это пример создания синглтона в классе базы данных

шаблоны дизайна 1) синглтон

class Database{
  public static $instance;
  public static function getInstance(){
    if(!isset(Database::$instance)){
    Database::$instance=new Database();

     return Database::$instance;
    }

  }

  $db=Database::getInstance();
  $db2=Database::getInstance();
  $db3=Database::getInstance();

  var_dump($db);
  var_dump($db2);
  var_dump($db3);

тогда выход -

  object(Database)[1]
  object(Database)[1]
  object(Database)[1]

использовать только один экземпляр, не создавать 3 экземпляра

0 голосов
/ 08 декабря 2014

Класс базы данных, который проверяет, существует ли какой-либо существующий экземпляр базы данных, он возвратит предыдущий экземпляр.

   class Database {  
        public static $instance;  
         public static function getInstance(){  
            if(!isset(Database::$instance) ) {  
                Database::$instance = new Database();  
            }  
           return Database::$instance;  
         }  
         private function __cunstruct() {  
           /* private and cant create multiple objects */  
         }  
         public function getQuery(){  
            return "Test Query Data";  
         }  
    }  
    $dbObj = Database::getInstance();  
    $dbObj2 = Database::getInstance();  
    var_dump($dbObj);  
    var_dump($dbObj2);  


/* 
After execution you will get following output: 

object(Database)[1] 
object(Database)[1] 

*/  

Ссылка http://www.phptechi.com/php-singleton-design-patterns-example.html

0 голосов
/ 02 июня 2014

Мне понравился метод @ jose-segura, использующий черты, но мне не нравилось определять статические переменные для подклассов. Ниже приведено решение, позволяющее избежать этого путем кэширования экземпляров в статической локальной переменной в метод фабрики, индексированный по имени класса:

<?php
trait Singleton {

  # Single point of entry for creating a new instance. For a given
  # class always returns the same instance.
  public static function instance(){
    static $instances = array();
    $class = get_called_class();
    if( !isset($instances[$class]) ) $instances[$class] = new $class();
    return $instances[$class];
  }

  # Kill traditional methods of creating new instances
  protected function __clone() {}
  protected function __construct() {}
}

Использование такое же, как у @ jose-segura, только статическая переменная не нужна в подклассах.

0 голосов
/ 13 ноября 2013

Это должен быть правильный путь Синглтона.

class Singleton {

    private static $instance;
    private $count = 0;

    protected function __construct(){

    }

    public static function singleton(){

        if (!isset(self::$instance)) {

            self::$instance = new Singleton;

        }

        return self::$instance;

    }

    public function increment()
    {
        return $this->count++;
    }

    protected function __clone(){

    }

    protected function __wakeup(){

    }

} 
0 голосов
/ 09 октября 2013

Я согласен с первым ответом, но я бы также объявил класс как окончательный, чтобы его нельзя было расширить, поскольку расширение синглтона нарушает шаблон синглтона. Также переменная экземпляра должна быть закрытой, чтобы к ней нельзя было получить прямой доступ. Также сделайте метод __clone закрытым, чтобы вы не могли клонировать одноэлементный объект.

Ниже приведен пример кода.

/**
 * Singleton class
 *
 */
final class UserFactory
{
    private static $_instance = null;

    /**
     * Private constructor
     *
     */
    private function __construct() {}

    /**
     * Private clone method
     *
     */
     private function __clone() {}

    /**
     * Call this method to get singleton
     *
     * @return UserFactory
     */
    public static function getInstance()
    {
        if (self::$_instance === null) {
            self::$_instance = new UserFactory();
        }
        return self::$_instance;
    }
}

Пример использования

$user_factory = UserFactory::getInstance();

Что это мешает вам сделать (что нарушит шаблон синглтона ..

ЭТО ВЫ НЕ МОЖЕТЕ СДЕЛАТЬ!

$user_factory = UserFactory::$_instance;

class SecondUserFactory extends UserFactory { }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...