О шаблоне singleton в php

Java база данных PHP C++

Шаблон Singleton: как следует из названия, существует только один экземпляр. В качестве шаблона создания объекта шаблон singleton гарантирует, что существует только один экземпляр класса, и он создает экземпляр самого себя и предоставляет этот экземпляр всей системе.

Зачем использовать шаблон singleton

1. Ограничения самого языка PHP

Язык PHP является интерпретируемым языком сценариев.Этот операционный механизм позволяет повторно использовать все связанные ресурсы после интерпретации и выполнения каждой страницы PHP. Другими словами, PHP не имеет возможности сделать объект резидентным в памяти на уровне языка.Это и asp.NET, Java и другие типы компиляции разные.Например, в Java синглтон всегда будет существовать в жизненном цикле всего приложения, а переменные кросс-страничного уровня, что реально может добиться уникальности этого экземпляра в приложении жизненный цикл. Однако в PHP все переменные, будь то глобальные переменные или статические члены класса, находятся на уровне страницы.Каждый раз при выполнении страницы будет пересоздаваться новый объект, который будет очищаться после страницы. Кажется, что одноэлементный режим PHP не имеет смысла, поэтому я думаю, что одноэлементный режим PHP имеет большое значение только тогда, когда в одном запросе на уровне страницы есть несколько сценариев приложения и необходимо совместно использовать одни и те же ресурсы объекта.

2. Сценарии применения

В приложении будет большое количество операций с базой данных, таких как поведение при подключении к базе данных через дескриптор базы данных.Использование одноэлементного режима может избежать большого количества новых операций, поскольку каждая новая операция будет потреблять ресурсы памяти и системы Ресурсы. Если в системе должен быть класс для глобального управления некоторой информацией о конфигурации, то использование шаблона singleton может быть очень удобным.

суть

  1. Класс может иметь только один объект
  2. Должен быть объектом этого класса, созданным самим собой
  3. Предоставить этот объект всей системе

Конкретная реализация

  1. Класс одноэлементного шаблона предоставляет только частный конструктор,
  2. Определение класса содержит статический частный объект класса,
  3. Этот класс предоставляет статическую общедоступную функцию для создания или получения собственного статического закрытого объекта.

Код

class Singleton{
        //存放实例 私有静态变量
        private static $_instance = null;

        //私有化构造方法、
        private function __construct(){
            echo "单例模式的实例被构造了";
        }
        //私有化克隆方法
        private function __clone(){

        }

        //公有化获取实例方法
        public static function getInstance(){
            if (!(self::$_instance instanceof Singleton)){
                self::$_instance = new Singleton();
            }
            return self::$_instance;
        }
    }

    $singleton=Singleton::getInstance();

Учебник по ООП

Тип оператора instanceof

<?php
class MyClass
{
}

class NotMyClass
{
}
$a = new MyClass;

var_dump($a instanceof MyClass);
var_dump($a instanceof NotMyClass);
?>

Приведенная выше процедура выведет:

bool(true)
bool(false)

instanceof используется для определения того, является ли переменная экземпляром объекта, реализующего класс, унаследованный класс или интерфейс. Если обнаруженная переменная не является объектом, instanceof не выдает никакого сообщения об ошибке, а возвращает FALSE. Не разрешено обнаруживать константы.

Волшебный метод __construct()

Конструктор объявляется закрытым, чтобы объект не создавался напрямую, поэтому new Singleton() сообщит об ошибке.

private function __construct() { echo 'Iam constructed'; }

Волшебный метод __clone()

Когда копирование класса будет завершено, если метод __clone() определен, метод __clone() во вновь созданном объекте (объект, сгенерированный копией) будет вызываться и может использоваться для изменения значения атрибута. (при необходимости). Private __clone предотвращает клонирование объектов этого класса. Примечание: объект клона не выполняет метод в __construct

Таким образом, мы предотвращаем клонирование объекта $singleton режима singleton. Есть два способа сделать это.

Первый способ: установить магический метод __clone(); разрешение на доступ закрытое Второй метод: если __clone() является общедоступным методом, добавьте в функцию пользовательскую ошибку.

// 阻止用户复制对象实例
public function __clone(){
    trigger_error('Clone is not allowed.',E_USER_ERROR);
}

Что касается __clone() , официальная документация PHP: после завершения закрытия, если определен метод __clone(), будет вызван метод __clone() вновь созданного объекта, чтобы разрешить любые необходимые свойства, которые необходимо изменить.

Ключевые слова клон и присвоение

class foo {
	public $bar = 'php';
}
$foo = new foo();

$a = $foo; // 标识符赋值(把$a赋值为null,原来的$foo并不会变成null,但通过$a能够修改$foo的成员$bar)
$a = &$foo; // 引用赋值(把$a赋值为null,原来的$foo也会跟着变成null)
$a = clone $foo; // 值赋值(赋值后互不影响,在计算机内存上的体现属于浅复制)

репликация объекта

В PHP операции присваивания между объектами на самом деле являются ссылочными операциями (на самом деле большинство языков программирования таковыми и являются! Основная причина — проблемы с памятью и производительностью), такие как:

class myclass {
public $data;
}
$obj1 = new myclass();
$obj1->data = "aaa";
$obj2 = $obj1;
$obj2->data ="bbb";     //$obj1->data的值也会变成"bbb"

так какobj1 ,obj2 — это ссылка на ту же область памяти, поэтому изменение любого объекта одновременно изменит другой объект.

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

class myclass {
public $data;
}
$obj1 = new myclass();
$obj1->data ="aaa";
$obj2 = clone $obj1;
$obj2->data ="bbb";     // $obj1->data的值仍然为"aaa"

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

мелкая копия

Какие? Принципиально независим? ! Что это означает? Поскольку клон объекта PHP использует метод неглубокого копирования, если элементы свойства в объекте имеют ссылочный тип, эти члены фактически не копируются после клонирования, но на них все еще ссылаются. (На самом деле, большинство других языков также реализованы таким образом. Если вы знакомы с концепциями памяти C++, копирования, конструктора копирования и т. д., вам легко понять эту концепцию), вот пример для иллюстрации :

class myClass{
public $data;
}

$sss ="aaa";
$obj1 = new myClass();
$obj1->data =&$sss;   //注意,这里是个reference!
$obj2 = clone $obj1;
$obj2->data="bbb";  //这时,$obj1->data的值变成了"bbb" 而不是"aaa"!

var_dump($obj1);
var_dump($obj2);

Давайте возьмем более практический пример, чтобы проиллюстрировать последствия поверхностного копирования клона PHP:

class testClass
{
   public $str_data;
   public $obj_data;
}

$dateTimeObj = new DateTime("2014-07-05", new DateTimeZone("UTC"));

$obj1 = new testClass();
$obj1->str_data ="aaa";
$obj1->obj_data = $dateTimeObj;

$obj2 = clone $obj1;

var_dump($obj1);    // str_data:"aaa"  obj_data:"2014-07-05 00:00:00"
var_dump($obj2);    // str_data:"aaa"  obj_data:"2014-07-05 00:00:00"

$obj2->str_data ="bbb";
$obj2->obj_data->add(new DateInterval('P10D'));      //给$obj2->obj_date 的时间增加了10天

var_dump($obj1);     // str_data:"aaa"   obj_data:"2014-07-15 00:00:00"  !!!!
var_dump($obj2);     // str_data:"bbb"   obj_data:"2014-07-15 00:00:00"
var_dump($dateTimeObj)  // 2014-07-15 00:00:00"

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

глубокая копия

$obj1->obj_data =$dateTimeObj 

Это предложение на самом деле является присваиванием ссылочного типа.Помните, что прямое присвоение объектов в PHP, упомянутое ранее, является ссылочной операцией? если вы не используетеobj1->obj_dat = clonedataTimeObj!

$obj2 = clone $obj1 

Это предложение создает неглубокую копию объекта obj1 и присваивает ее объекту obj2.Поскольку это неглубокая копия, obj_data в obj2 также является ссылкой на $dateTimeObj!

3)

$dateTimeObj,
$obj1->obj_data, 
$obj2->obj_data

На самом деле это ссылка на одни и те же данные объекта области памяти, поэтому изменение одного из них повлияет на два других!

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

class testClass
{
 public $str_data;
 public $obj_data;

 public function __clone() {
   $this->obj_data = clone $this->obj_data;
}

$dateTimeObj = new DateTime("2014-07-05", new DateTimeZone("UTC"));

$obj1 = new testClass();
$obj1->str_data ="aaa";
$obj1->obj_data = $dateTimeObj;

$obj2 = clone $obj1;
var_dump($obj1);  // str_data:"aaa"  obj_data:"2014-07-05 00:00:00"
var_dump($obj2);  // str_data:"aaa"  obj_data:"2014-07-05 00:00:00"
$obj2->str_data ="bbb";
$obj2->obj_data->add(new DateInterval('P10D'));

var_dump($obj1);  // str_data:"aaa"  obj_data:"2014-07-05 00:00:00"
var_dump($obj2);  // str_data:"aaa"  obj_data:"2014-07-15 00:00:00"
var_dump($dateTimeObj);  //"2014-07-05 00:00:00"