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


답변

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

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


답변

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

private function __clone() {}

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

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

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


답변

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


답변

protected  static $_instance;

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

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