PHP5 클래스를 사용하여 어떻게 싱글 톤 클래스를 만들 수 있습니까?
PHP5 클래스를 사용하여 어떻게 싱글 톤 클래스를 만들 수 있습니까?
답변:
/**
* Singleton class
*
*/
final class UserFactory
{
/**
* Call this method to get singleton
*
* @return UserFactory
*/
public static function Instance()
{
static $inst = null;
if ($inst === null) {
$inst = new UserFactory();
}
return $inst;
}
/**
* Private ctor so nobody else can instantiate it
*
*/
private function __construct()
{
}
}
쓰다:
$fact = UserFactory::Instance();
$fact2 = UserFactory::Instance();
$fact == $fact2;
그러나:
$fact = new UserFactory()
오류가 발생합니다.
정적 변수 범위 및 설정 작동 이유를 이해하려면 http://php.net/manual/en/language.variables.scope.php#language.variables.scope.static 을 참조 하십시오static $inst = null;
.
PHP 5.3에서는 늦은 정적 바인딩을 통해 상속 가능한 Singleton 클래스를 만들 수 있습니다.
class Singleton
{
protected static $instance = null;
protected function __construct()
{
//Thou shalt not construct that which is unconstructable!
}
protected function __clone()
{
//Me not like clones! Me smash clones!
}
public static function getInstance()
{
if (!isset(static::$instance)) {
static::$instance = new static;
}
return static::$instance;
}
}
이것은 PHP 5.3 이전에 싱글 톤을 확장 한 클래스가 자신의 부모 클래스의 인스턴스를 생성하는 것이 아니라는 문제를 해결합니다.
이제 할 수있는 일 :
class Foobar extends Singleton {};
$foo = Foobar::getInstance();
그리고 $ foo는 Singleton 인스턴스 대신 Foobar 인스턴스가됩니다.
"subclass should own its own static var. check this: echo get_class(Foobar::getInstance());echo get_class(Singleton::getInstance());"
.
$instance
서브 클래스가 아닌 싱글 톤에 있습니다. 일부 서브 클래스가 인스턴스화되면 getInstance ()는 모든 서브 클래스에 대해 해당 인스턴스를 리턴합니다.
불행히도 여러 개의 서브 클래스가있는 경우 Inwdr의 답변 이 중단됩니다.
올바른 상속 가능한 Singleton 기본 클래스는 다음과 같습니다.
class Singleton
{
private static $instances = array();
protected function __construct() {}
protected function __clone() {}
public function __wakeup()
{
throw new Exception("Cannot unserialize singleton");
}
public static function getInstance()
{
$cls = get_called_class(); // late-static-bound class name
if (!isset(self::$instances[$cls])) {
self::$instances[$cls] = new static;
}
return self::$instances[$cls];
}
}
테스트 코드 :
class Foo extends Singleton {}
class Bar extends Singleton {}
echo get_class(Foo::getInstance()) . "\n";
echo get_class(Bar::getInstance()) . "\n";
싱글 톤 패턴을 만드는 실제적이고 현대적인 방법은 다음과 같습니다.
<?php
/**
* Singleton Pattern.
*
* Modern implementation.
*/
class Singleton
{
/**
* Call this method to get singleton
*/
public static function instance()
{
static $instance = false;
if( $instance === false )
{
// Late static binding (PHP 5.3+)
$instance = new static();
}
return $instance;
}
/**
* Make constructor private, so nobody can call "new Class".
*/
private function __construct() {}
/**
* Make clone magic method private, so nobody can clone instance.
*/
private function __clone() {}
/**
* Make sleep magic method private, so nobody can serialize instance.
*/
private function __sleep() {}
/**
* Make wakeup magic method private, so nobody can unserialize instance.
*/
private function __wakeup() {}
}
그래서 지금처럼 사용할 수 있습니다.
<?php
/**
* Database.
*
* Inherited from Singleton, so it's now got singleton behavior.
*/
class Database extends Singleton {
protected $label;
/**
* Example of that singleton is working correctly.
*/
public function setLabel($label)
{
$this->label = $label;
}
public function getLabel()
{
return $this->label;
}
}
// create first instance
$database = Database::instance();
$database->setLabel('Abraham');
echo $database->getLabel() . PHP_EOL;
// now try to create other instance as well
$other_db = Database::instance();
echo $other_db->getLabel() . PHP_EOL; // Abraham
$other_db->setLabel('Priler');
echo $database->getLabel() . PHP_EOL; // Priler
echo $other_db->getLabel() . PHP_EOL; // Priler
보시다시피이 실현은 훨씬 유연합니다.
instance
기능 $instance
해야 null
하지false
<?php
/**
* Singleton patter in php
**/
trait SingletonTrait {
protected static $inst = null;
/**
* call this method to get instance
**/
public static function getInstance(){
if (static::$inst === null){
static::$inst = new static();
}
return static::$inst;
}
/**
* protected to prevent clonning
**/
protected function __clone(){
}
/**
* protected so no one else can instance it
**/
protected function __construct(){
}
}
쓰다:
/**
* example of class definitions using SingletonTrait
*/
class DBFactory {
/**
* we are adding the trait here
**/
use SingletonTrait;
/**
* This class will have a single db connection as an example
**/
protected $db;
/**
* as an example we will create a PDO connection
**/
protected function __construct(){
$this->db =
new PDO('mysql:dbname=foodb;port=3305;host=127.0.0.1','foouser','foopass');
}
}
class DBFactoryChild extends DBFactory {
/**
* we repeating the inst so that it will differentiate it
* from UserFactory singleton
**/
protected static $inst = null;
}
/**
* example of instanciating the classes
*/
$uf0 = DBFactoryChild::getInstance();
var_dump($uf0);
$uf1 = DBFactory::getInstance();
var_dump($uf1);
echo $uf0 === $uf1;
respose :
object(DBFactoryChild)#1 (0) {
}
object(DBFactory)#2 (0) {
}
PHP 5.4를 사용하는 경우 : 옵션의 특성 을 나타내므로 Singleton 패턴 을 얻기 위해 상속 계층 구조를 낭비하지 않아도됩니다.
사용 여부도 통지 있다는 특성을 또는 싱글 확장 클래스를 하나 개의 느슨한 끝은 다음 코드 행을 추가 해달라고하면 자식 클래스의 싱글 톤을 만드는 것이 었습니다 :
protected static $inst = null;
어린이 수업에서
예기치 않은 결과는 다음과 같습니다.
object(DBFactoryChild)#1 (0) {
}
object(DBFactoryChild)#1 (0) {
}
이 방법은 원하는 모든 클래스에 싱글 톤을 적용합니다. 싱글 톤을 만들려는 클래스에 1 개의 메소드를 추가하면됩니다.
또한 개체를 "SingleTonBase"클래스에 저장하므로 개체를 반복하여 시스템에서 사용한 모든 개체를 디버깅 할 수 있습니다 SingleTonBase
.
SingletonBase.php라는 파일을 만들어 스크립트의 루트에 포함 시키십시오!
코드는
abstract class SingletonBase
{
private static $storage = array();
public static function Singleton($class)
{
if(in_array($class,self::$storage))
{
return self::$storage[$class];
}
return self::$storage[$class] = new $class();
}
public static function storage()
{
return self::$storage;
}
}
그런 다음 모든 클래스에 대해 싱글 톤을 만들려면이 작은 단일 메소드를 추가하십시오.
public static function Singleton()
{
return SingletonBase::Singleton(get_class());
}
다음은 작은 예입니다.
include 'libraries/SingletonBase.resource.php';
class Database
{
//Add that singleton function.
public static function Singleton()
{
return SingletonBase::Singleton(get_class());
}
public function run()
{
echo 'running...';
}
}
$Database = Database::Singleton();
$Database->run();
그리고 당신은 당신이 가진 모든 클래스 에서이 싱글 톤 함수를 추가 할 수 있으며 클래스 당 하나의 인스턴스 만 생성합니다.
참고 : newClass ()를 사용하지 않으려면 __construct를 항상 private으로 만들어야합니다. 인스턴스화.
class Database{
//variable to hold db connection
private $db;
//note we used static variable,beacuse an instance cannot be used to refer this
public static $instance;
//note constructor is private so that classcannot be instantiated
private function __construct(){
//code connect to database
}
//to prevent loop hole in PHP so that the class cannot be cloned
private function __clone() {}
//used static function so that, this can be called from other classes
public static function getInstance(){
if( !(self::$instance instanceof self) ){
self::$instance = new self();
}
return self::$instance;
}
public function query($sql){
//code to run the query
}
}
Access the method getInstance using
$db = Singleton::getInstance();
$db->query();
반 패턴으로 간주되므로 싱글 톤 패턴을 실제로 사용할 필요는 없습니다. 기본적으로이 패턴을 전혀 구현하지 않는 데에는 많은 이유가 있습니다. PHP singleton 클래스에 대한 모범 사례 로 시작하십시오 .
결국 싱글 톤 패턴을 사용해야한다고 생각한다면 SingletonClassVendor 추상 클래스를 확장하여 싱글 톤 기능을 얻을 수있는 클래스를 작성할 수 있습니다.
이것이이 문제를 해결하기 위해 제공 한 것입니다.
<?php
namespace wl;
/**
* @author DevWL
* @dosc allows only one instance for each extending class.
* it acts a litle bit as registry from the SingletonClassVendor abstract class point of view
* but it provides a valid singleton behaviour for its children classes
* Be aware, the singleton pattern is consider to be an anti-pattern
* mostly because it can be hard to debug and it comes with some limitations.
* In most cases you do not need to use singleton pattern
* so take a longer moment to think about it before you use it.
*/
abstract class SingletonClassVendor
{
/**
* holds an single instance of the child class
*
* @var array of objects
*/
protected static $instance = [];
/**
* @desc provides a single slot to hold an instance interchanble between all child classes.
* @return object
*/
public static final function getInstance(){
$class = get_called_class(); // or get_class(new static());
if(!isset(self::$instance[$class]) || !self::$instance[$class] instanceof $class){
self::$instance[$class] = new static(); // create and instance of child class which extends Singleton super class
echo "new ". $class . PHP_EOL; // remove this line after testing
return self::$instance[$class]; // remove this line after testing
}
echo "old ". $class . PHP_EOL; // remove this line after testing
return static::$instance[$class];
}
/**
* Make constructor abstract to force protected implementation of the __constructor() method, so that nobody can call directly "new Class()".
*/
abstract protected function __construct();
/**
* Make clone magic method private, so nobody can clone instance.
*/
private function __clone() {}
/**
* Make sleep magic method private, so nobody can serialize instance.
*/
private function __sleep() {}
/**
* Make wakeup magic method private, so nobody can unserialize instance.
*/
private function __wakeup() {}
}
사용 예 :
/**
* EXAMPLE
*/
/**
* @example 1 - Database class by extending SingletonClassVendor abstract class becomes fully functional singleton
* __constructor must be set to protected becaouse:
* 1 to allow instansiation from parent class
* 2 to prevent direct instanciation of object with "new" keword.
* 3 to meet requierments of SingletonClassVendor abstract class
*/
class Database extends SingletonClassVendor
{
public $type = "SomeClass";
protected function __construct(){
echo "DDDDDDDDD". PHP_EOL; // remove this line after testing
}
}
/**
* @example 2 - Config ...
*/
class Config extends SingletonClassVendor
{
public $name = "Config";
protected function __construct(){
echo "CCCCCCCCCC" . PHP_EOL; // remove this line after testing
}
}
예상대로 작동한다는 것을 증명하기 위해 :
/**
* TESTING
*/
$bd1 = Database::getInstance(); // new
$bd2 = Database::getInstance(); // old
$bd3 = Config::getInstance(); // new
$bd4 = Config::getInstance(); // old
$bd5 = Config::getInstance(); // old
$bd6 = Database::getInstance(); // old
$bd7 = Database::getInstance(); // old
$bd8 = Config::getInstance(); // old
echo PHP_EOL."COMPARE ALL DATABASE INSTANCES".PHP_EOL;
var_dump($bd1);
echo '$bd1 === $bd2' . ($bd1 === $bd2)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd2 === $bd6' . ($bd2 === $bd6)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd6 === $bd7' . ($bd6 === $bd7)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo PHP_EOL;
echo PHP_EOL."COMPARE ALL CONFIG INSTANCES". PHP_EOL;
var_dump($bd3);
echo '$bd3 === $bd4' . ($bd3 === $bd4)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd4 === $bd5' . ($bd4 === $bd5)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
echo '$bd5 === $bd8' . ($bd5 === $bd8)? ' TRUE' . PHP_EOL: ' FALSE' . PHP_EOL; // TRUE
이 모든 복잡성 ( "late static binding"... harumph)은 PHP의 깨진 객체 / 클래스 모델의 표시 일뿐입니다. 클래스 객체가 일류 객체 인 경우 (Python 참조) "$ _instance"는 클래스 인스턴스 변수 (클래스 객체의 멤버, 인스턴스의 멤버 / 속성 및 공유와는 반대)가됩니다. 그 후손들에 의해. 스몰 토크 세계에서는 이것이 "클래스 변수"와 "클래스 인스턴스 변수"의 차이입니다.
PHP에서는 패턴이 코드 작성을위한 가이드라는 지침을 기억해야하는 것처럼 보입니다. 싱글 톤 템플릿에 대해 생각할 수도 있지만 실제 "Singleton"클래스에서 상속되는 코드를 작성하려고합니다. PHP에 대해 잘못 안내 된 것처럼 보입니다 (나는 진취적인 영혼이 적절한 SVN 키워드를 만들 수 있다고 생각했지만).
공유 템플릿을 사용하여 각 싱글 톤을 개별적으로 계속 코딩 할 것입니다.
나는 싱글 톤 이블 토론에서 절대적으로 벗어나지 않는다. 인생은 너무 짧다.
나는 이것이 불필요하게 화염 전쟁을 일으킬 것이라고 알고 있지만, 하나 이상의 데이터베이스 연결을 원하는 방법을 알 수 있으므로 싱글 톤이 그에 대한 최상의 솔루션이 아닐 수 있다는 점을 인정할 것입니다 ... 내가 매우 유용하다고 생각하는 싱글 톤 패턴의 다른 용도.
예를 들면 다음과 같습니다. 실제로 가벼운 것을 원했기 때문에 내 MVC 및 템플릿 엔진을 굴리기로 결정했습니다. 그러나 표시하려는 데이터에는 ≥ 및 μ와 같은 특수 수학 문자가 많이 포함되어 있습니다. 데이터는 HTML로 사전 인코딩되지 않고 데이터베이스에 실제 UTF-8 문자로 저장됩니다. 내 앱은 HTML 외에도 PDF 및 CSV와 같은 다른 형식을 제공 할 수 있습니다. HTML 형식을 지정하기에 적절한 위치는 해당 페이지 섹션 (스 니펫)을 렌더링하는 템플릿 (있는 경우 "보기") 내에 있습니다. 적절한 HTML 엔티티로 변환하고 싶지만 PHP get_html_translation_table () 함수는 빠르지 않습니다. 한 번만 데이터를 검색하고 배열로 저장하여 모든 사람이 사용할 수 있도록하는 것이 더 좋습니다. 여기' sa 샘플 나는 속도를 테스트하기 위해 함께 노크. 아마도 이것은 인스턴스를 가져온 후 사용하는 다른 메소드가 정적인지 여부에 관계없이 작동합니다.
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 런타임 : 싱글 톤을 사용하여 27.842966794968 초 런타임 : 싱글 톤을 사용하지 않고 237.78191494942 초
따라서 확실히 전문가는 아니지만 특정 종류의 데이터에 대한 느린 호출의 오버 헤드를 줄이는 더 편리하고 신뢰할 수있는 방법은 보이지 않지만 매우 간단합니다 (필요한 작업을 수행하는 단일 코드 라인). 내 예제에는 유용한 방법이 하나뿐이므로 전역 적으로 정의 된 함수보다 낫지는 않지만 두 가지 방법이 있으면 즉시 그룹화하고 싶습니까? 내가 기지에서 벗어나나요?
또한, 실제로는 무언가를하는 예제를 선호합니다. 때때로 예제에 "// 여기에 유용한 무언가"와 같은 문장이 포함되어있을 때 시각화하기가 어렵 기 때문에 튜토리얼을 검색 할 때 항상 보게됩니다.
어쨌든,이 유형의 물건에 싱글 톤을 사용하는 것이 왜 해로운 지 또는 지나치게 복잡한 지에 대한 의견이나 의견을 듣고 싶습니다.
이 기사는 주제를 매우 광범위하게 다루고 있습니다 : http://www.phptherightway.com/pages/Design-Patterns.html#singleton
다음에 유의하십시오.
- 생성자
__construct()
는 연산자protected
를 통해 클래스 외부에 새 인스턴스를 만들지 못하도록 선언됩니다new
.- 매직 메소드
__clone()
는 연산자private
를 통해 클래스 인스턴스를 복제하지 못하도록 선언되어clone
있습니다.- 매직 메소드
__wakeup()
는private
전역 함수를 통해 클래스 인스턴스의 직렬화를 방지 하는 것으로 선언됩니다unserialize()
.getInstance()
키워드를 사용하여 정적 작성 방법에서 늦은 정적 바인딩을 통해 새 인스턴스가 작성됩니다static
. 이것은class Singleton
예제에서 서브 클래 싱을 허용합니다 .
나는 여기에 공유 할 생각을 오래 전부터 작성했습니다.
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();
첫 번째 답변에 동의하지만 클래스를 최종 클래스로 선언하여 싱글 톤을 확장하면 싱글 톤 패턴을 위반하므로 확장 할 수 없습니다. 또한 인스턴스 변수는 개인용이어야하므로 직접 액세스 할 수 없습니다. 또한 싱글 톤 객체를 복제 할 수 없도록 __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 { }
이것이 싱글턴의 올바른 방법이어야합니다.
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(){
}
}
나는 특성을 사용하는 @ 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와 동일하며 하위 클래스의 정적 변수가 필요하지 않습니다.
기존 데이터베이스 인스턴스가 있는지 확인하는 데이터베이스 클래스는 이전 인스턴스를 리턴합니다.
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
데이터베이스 클래스에서 싱글 톤을 만드는 예입니다.
디자인 패턴 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 개의 인스턴스를 만들지 않고 단일 인스턴스 만 사용
빠른 예 :
final class Singleton
{
private static $instance = null;
private function __construct(){}
private function __clone(){}
private function __wakeup(){}
public static function get_instance()
{
if ( static::$instance === null ) {
static::$instance = new static();
}
return static::$instance;
}
}
도움을 바랍니다.
다음은 $ 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();