PHP5에서 싱글 톤 디자인 패턴 만들기


204

PHP5 클래스를 사용하여 어떻게 싱글 톤 클래스를 만들 수 있습니까?



1
@Andrew 그런 다음 데이터베이스에 연결하는 두 번째 인스턴스를 인스턴스화하지 마십시오. 해당 인스턴스를 필요한 곳으로 전달하십시오. 싱글 톤의 필요성은 코드 냄새입니다. gooh.posterous.com/singletons-in-php
Gordon

3
@Andrew Mmmmkay. 위반은 없지만이 논의를 계속하기 전에 소프트웨어 품질에 관한 책을받는 것이 좋습니다. 싱글 톤은 단순화되지 않고 정상적인 유지 보수 및 개발을 복잡하게합니다. 사실, 그것은 다른 방향으로 진행됩니다 : 처음부터 개발을 단순화하고 가능하게하는 단위 테스트입니다.
Gordon

3
@Andrew : 이제 하나의 데이터베이스 연결 만 필요하다고 가정합니다. 요구 사항이 변경되어 실제로 2 개의 데이터베이스 서버와 통신해야 할 경우 어떻게됩니까? 팀이 올바른 일 을한다고 믿을 수 없다면 말할 것도없고 , 싱글 톤을 만들면 최소한 도움이되지 않습니다. 처음부터 올바르게 작업하고 신뢰할 수있는 팀을 구성하면 괜찮을 것입니다.
ircmaxell

4
싱글 톤이 과도하게 사용되었다고해서 피해야 할 나쁜 패턴은 아닙니다. 싱글 톤을 싫어하지 마십시오. 때로는 특정 문제에 대한 완벽한 솔루션입니다. 감정적으로 타락시키는 대신에 사용해서는 안되는 이유를 더 잘 설명 할 수 있습니다.
Gilles Lesire

답변:


268
/**
 * 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; .


59
두 인스턴스를 비교하려면 == 대신 ===를 사용해야합니다. $ fact1과 $ fact2가 모두 같은 클래스 인 경우 ==가 true를 리턴하지만, 둘 다 동일한 오브젝트의 동일한 인스턴스 인 경우에만 true를 리턴합니다.
Keith Twombley

10
복제 방법도 비공개입니다
Alex Petrov

22
이 메소드는 Instance ()를 호출 할 때마다 UserFactory 인스턴스를 널로 재설정하지 않습니까? java에서 $ inst 변수는 개인 정적 속성이며 반복해서 재설정해서는 안됩니다. 그렇지 않으면 싱글 톤으로 만들 수 없습니다.
Rudy Garcia

8
다음은 저자가 의도 한대로
hereswhatidid

10
$ inst = new self ();를 사용해야합니다. not $ inst = new UserFactory (); 나중에 이것을 건너 오는 사람을 위해. 내장 된 PHP 방법론을 사용하기위한 +1
Ligemer

119

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 인스턴스가됩니다.


1
늦은 정적 바인딩은 실제로 PHP 5.3에서 매우 좋습니다. 여전히 사용할 수 없습니다.
AntonioCS

4
@ggsonic에서 : "subclass should own its own static var. check this: echo get_class(Foobar::getInstance());echo get_class(Singleton::getInstance());".
Brock Adams

4
이것은 전혀 작동하지 않습니다. Foobar가 당신이 만든 첫 번째 클래스였습니까?
Chris KL

1
여전히 복제 가능성 ..... "$ a = Singleton :: getInstance (); $ b = unserialize (serialize ($ a)); $ a! == $ b;"
bortunac

15
하나 이상의 서브 클래스가있는 경우 작동하지 않습니다! $instance서브 클래스가 아닌 싱글 톤에 있습니다. 일부 서브 클래스가 인스턴스화되면 getInstance ()는 모든 서브 클래스에 대해 해당 인스턴스를 리턴합니다.
mpartel April

116

불행히도 여러 개의 서브 클래스가있는 경우 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";

1
이것은 싱글 톤 구현을 수정하는 데 가장 가깝습니다. 직렬화 해제를 방지하기 위해 __wakeup () 메서드를 throw하는 것도 고려해야 합니다.
Robert Rossmann

실제로 예외를 던지거나 수동으로 오류를 제기해야합니다. 보호 / 개인으로 함수를 선언하면 E_WARNING 만 발생하여 메소드에 액세스 할 수 없으며 계속 진행할 것입니다.
Robert Rossmann

감사. 나는 일반적으로 모든 경고 등을 예외로 바꿨으므로 테스트 할 때의 차이점을 잊어 버렸습니다 : P
mpartel

이것이 여러 하위 클래스를 올바르게 처리하는 유일한 솔루션입니다. 감사합니다!
밥 Dankert

36

싱글 톤 패턴을 만드는 실제적이고 현대적인 방법은 다음과 같습니다.

<?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

보시다시피이 실현은 훨씬 유연합니다.


4
이 스레드에서 싱글 톤 패턴에 대한 가장 명확한 대답입니다. 감사.
거스

이 접근법을 구현했으며 지정된대로 작동합니다. 두 번째 인스턴스가 null이됩니다. 그러나 구체적인 클래스를 확장 할 필요도 없었습니다. 방금 해당 콘크리트 클래스의 생성자에서 Singleton :: instance ()를 구현했습니다.
snaphuman

에서 instance기능 $instance해야 null하지false
Mifas

그러나 기능은 아니지만 방법입니다.
Abraham Tugalov

26

인스턴스 복제를 허용하지 않으려면 전용 __clone () 메서드를 추가해야합니다.

private function __clone() {}

이 방법을 포함하지 않으면 다음이 가능해집니다.

$inst1=UserFactory::Instance(); // to stick with the example provided above
$inst2=clone $inst1;

이제 $inst1! == $inst2-더 이상 같은 인스턴스가 아닙니다.


11
<?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) {
}

10
protected  static $_instance;

public static function getInstance()
{
    if(is_null(self::$_instance))
    {
        self::$_instance = new self();
    }
    return self::$_instance;
}

이 코드는 클래스 이름을 신경 쓰지 않고 모든 클래스에 적용될 수 있습니다.


8

클래스 당 한 줄로 여러 개체를 지원합니다.

이 방법은 원하는 모든 클래스에 싱글 톤을 적용합니다. 싱글 톤을 만들려는 클래스에 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으로 만들어야합니다. 인스턴스화.


5
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();

5

반 패턴으로 간주되므로 싱글 톤 패턴을 실제로 사용할 필요는 없습니다. 기본적으로이 패턴을 전혀 구현하지 않는 데에는 많은 이유가 있습니다. 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

더 많은 답변을 읽는 동안 나는 이와 같은 것을 염두에 두었다. 운 좋게 그것은 이미 여기에 있었다 :)
hatef

3

이 모든 복잡성 ( "late static binding"... harumph)은 PHP의 깨진 객체 / 클래스 모델의 표시 일뿐입니다. 클래스 객체가 일류 객체 인 경우 (Python 참조) "$ _instance"는 클래스 인스턴스 변수 (클래스 객체의 멤버, 인스턴스의 멤버 / 속성 및 공유와는 반대)가됩니다. 그 후손들에 의해. 스몰 토크 세계에서는 이것이 "클래스 변수"와 "클래스 인스턴스 변수"의 차이입니다.

PHP에서는 패턴이 코드 작성을위한 가이드라는 지침을 기억해야하는 것처럼 보입니다. 싱글 톤 템플릿에 대해 생각할 수도 있지만 실제 "Singleton"클래스에서 상속되는 코드를 작성하려고합니다. PHP에 대해 잘못 안내 된 것처럼 보입니다 (나는 진취적인 영혼이 적절한 SVN 키워드를 만들 수 있다고 생각했지만).

공유 템플릿을 사용하여 각 싱글 톤을 개별적으로 계속 코딩 할 것입니다.

나는 싱글 톤 이블 토론에서 절대적으로 벗어나지 않는다. 인생은 너무 짧다.


점점 더 복잡 해지는 PHP 언어를 볼 때주의해야합니다. 너무 많은 코딩 패러다임에서 너무 많은 다른 디자인 홀에서 벗어나기 위해 너무 많은 새로운 키워드가 추가되는 것 같습니다. 더 나쁜 것은, 높은 변경 률과 호스트 및 개발 플랫폼의 버전 왜곡으로 인해 오늘날의 "솔루션 뒤 주르"(@Eric Anderson의 답변과 같은 특성 [ stackoverflow.com/a/23998306/3696363], )가 작동하지 않음 "최신, 가장 큰"대신 "안정된"버전을 실행하는 프로덕션 시스템에서.
Eliyahu Skoczylas

2

나는 이것이 불필요하게 화염 전쟁을 일으킬 것이라고 알고 있지만, 하나 이상의 데이터베이스 연결을 원하는 방법을 알 수 있으므로 싱글 톤이 그에 대한 최상의 솔루션이 아닐 수 있다는 점을 인정할 것입니다 ... 내가 매우 유용하다고 생각하는 싱글 톤 패턴의 다른 용도.

예를 들면 다음과 같습니다. 실제로 가벼운 것을 원했기 때문에 내 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 초

따라서 확실히 전문가는 아니지만 특정 종류의 데이터에 대한 느린 호출의 오버 헤드를 줄이는 더 편리하고 신뢰할 수있는 방법은 보이지 않지만 매우 간단합니다 (필요한 작업을 수행하는 단일 코드 라인). 내 예제에는 유용한 방법이 하나뿐이므로 전역 적으로 정의 된 함수보다 낫지는 않지만 두 가지 방법이 있으면 즉시 그룹화하고 싶습니까? 내가 기지에서 벗어나나요?

또한, 실제로는 무언가를하는 예제를 선호합니다. 때때로 예제에 "// 여기에 유용한 무언가"와 같은 문장이 포함되어있을 때 시각화하기가 어렵 기 때문에 튜토리얼을 검색 할 때 항상 보게됩니다.

어쨌든,이 유형의 물건에 싱글 톤을 사용하는 것이 왜 해로운 지 또는 지나치게 복잡한 지에 대한 의견이나 의견을 듣고 싶습니다.


1

이 기사는 주제를 매우 광범위하게 다루고 있습니다 : http://www.phptherightway.com/pages/Design-Patterns.html#singleton

다음에 유의하십시오.

  • 생성자 __construct()는 연산자 protected를 통해 클래스 외부에 새 인스턴스를 만들지 못하도록 선언됩니다 new.
  • 매직 메소드 __clone()는 연산자 private를 통해 클래스 인스턴스를 복제하지 못하도록 선언되어 clone있습니다.
  • 매직 메소드 __wakeup()private전역 함수를 통해 클래스 인스턴스의 직렬화를 방지 하는 것으로 선언됩니다 unserialize().
  • getInstance()키워드를 사용하여 정적 작성 방법에서 늦은 정적 바인딩을 통해 새 인스턴스가 작성됩니다 static. 이것은 class Singleton예제에서 서브 클래 싱을 허용합니다 .

1

나는 여기에 공유 할 생각을 오래 전부터 작성했습니다.

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();

0

첫 번째 답변에 동의하지만 클래스를 최종 클래스로 선언하여 싱글 톤을 확장하면 싱글 톤 패턴을 위반하므로 확장 할 수 없습니다. 또한 인스턴스 변수는 개인용이어야하므로 직접 액세스 할 수 없습니다. 또한 싱글 톤 객체를 복제 할 수 없도록 __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 { }

0

이것이 싱글턴의 올바른 방법이어야합니다.

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

나는 특성을 사용하는 @ 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

기존 데이터베이스 인스턴스가 있는지 확인하는 데이터베이스 클래스는 이전 인스턴스를 리턴합니다.

   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

데이터베이스 클래스에서 싱글 톤을 만드는 예입니다.

디자인 패턴 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

빠른 예 :

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;
    }
}

도움을 바랍니다.


-4

다음은 $ 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();

5
싱글 톤이 아닌 것을 제외하고. Singleton 클래스의 인스턴스를 여러 개 만들 수 있습니다.
Andrew Moore

Singleton 클래스에서 어떤 인스턴스가 영향을 받더라도 Singleton의 모든 인스턴스에 대한 변경 사항이 있기 때문에 결국이라고 생각합니다. 위의 두 가지 기능을 추가했습니다. 이제 한 인스턴스에서 데이터를 수정하고 다른 인스턴스를 확인해 봅시다. 그렇다면 싱글 톤이 아니고 그렇지 않은 경우 무엇이 잘못 되었습니까?
bboydev

5
싱글 톤은 하나의 인스턴스 만 허용하는 클래스입니다. 여러 인스턴스를 만들면 해당 원칙이 무효화됩니다.
앤드류 무어
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.