PHP5でのシングルトンデザインパターンの作成


204

PHP5クラスを使用してシングルトンクラスをどのように作成しますか?



1
@Andrewデータベースに接続する2番目のインスタンスをインスタンス化しないでください。そのインスタンスを必要な場所に渡します。シングルトンの必要性はコードの匂いです。gooh.posterous.com/singletons-in-phpの
ゴードン

3
@Andrew Mmmmkay。問題はありませんが、この議論を続ける前に、ソフトウェアの品質に関する本を入手することをお勧めします。シングルトンは単純化されませんが、通常のメンテナンスと開発を複雑にします。実際、それは逆の方法です。そもそも開発を単純化して有効にする単体テストです。
ゴードン

3
@Andrew:データベース接続が1つだけ必要であると仮定します。要件が変更され、実際に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
2つのインスタンスを比較するには、==ではなく===を使用する必要があります。==は、$ fact1と$ fact2の両方が同じクラスの場合にtrueを返しますが、===は、同じオブジェクトの同じインスタンスの場合にのみtrueを返します。
キース・トゥーンブリー、2008年

10
cloneメソッドもプライベートにする必要があります
Alex Petrov 2013

22
このメソッドは、Instance()を呼び出すたびにUserFactoryのインスタンスをnullにリセットしませんか?Javaでは、$ inst変数はプライベートスタティック属性であり、これを何度もリセットすることはできません。そうでなければ、シングルトンにしない方がよいでしょう。
Rudy Garcia

8
作成者の意図するとおりに、関数内で変数をstaticとして宣言する理由と動作を以下に示します。php.net
en

10
$ inst = new self();を使用する必要があります。$ inst = new UserFactory();ではありません 後でこれに遭遇する人のために。組み込みのPHP方法論を使用するための+1。
Ligemer、2015

119

PHP 5.3では、遅延静的バインディングを介して継承可能なシングルトンクラスを作成できます。

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

これは問題を解決します。PHP5.3より前のバージョンでは、シングルトンを拡張したクラスは、それ自体ではなく親クラスのインスタンスを生成していました。

今あなたはできる:

class Foobar extends Singleton {};
$foo = Foobar::getInstance();

また、$ fooはシングルトンのインスタンスではなく、Foobarのインスタンスになります。


1
遅延静的バインディングは、PHP 5.3で非常に優れています。残念ながら、まだ使用できません。
AntonioCS 2009

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 2012

1
クローンを作成する可能性はまだあります... "$ a = Singleton :: getInstance(); $ b = unserialize(serialize($ a)); $ a!== $ b;"
bortunac

15
複数のサブクラスがある場合、これは機能しません!$instanceサブクラスではなくシングルトンにあります。サブクラスがインスタンス化されると、getInstance()はすべてのサブクラスのインスタンスを返します。
mpartel 2013

116

残念ながら、Inwdrの答えは、複数のサブクラスがあると壊れます。

これが正しい継承可能なシングルトン基本クラスです。

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()メソッドをスローすることも検討する必要があります。
Robert Rossmann 2013年

実際には、例外をスローするか、エラーを手動で発生させる必要があります。関数をprotected / privateとして宣言すると、メソッドにアクセスできないというE_WARNINGが発生するだけで、それ以外の場合は続行されます。
Robert Rossmann 2013年

ありがとう。私は通常、すべての警告などを例外に変えているので、テストしたときの違いを忘れていました:P
mpartel

これは、複数のサブクラスを適切に処理する唯一の解決策です。ありがとうございました!
ボブ・ダンケルト

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
これは、このスレッド内のシングルトンパターンに関する最も明確な答えです。ありがとう。
Gus

私はこのアプローチを実装しましたが、想定どおりに機能します。2番目のインスタンスはnullになります。ただし、具象クラスを拡張する必要もありませんでした。その具象クラスのコンストラクターにSingleton :: instance()を実装しました。
snaphuman 2017年

instance機能$instanceする必要がありnullませんfalse
Mifas

うん、でもそれは機能ではなく方法です。
アブラハムトゥガロフ2017年

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;

休息:

object(DBFactoryChild)#1 (0) {
}
object(DBFactory)#2 (0) {
}

あなたは、PHP 5.4を使用している場合:特色あなたが持っているために、継承階層を無駄にする必要はありませんので、そのオプションをSingletonパターンを

そしてまた、あなたが使用しているかどうかという通知の特性をまたはシングルトン拡張クラス1緩いエンドを使用すると、次のコード行を追加していけない場合は、子クラスのシングルトンを作成することでした。

   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行で複数のオブジェクトをサポート:

このメソッドは、必要なすべてのクラスにシングルトンを適用します。シングルトンにしたいクラスに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();

また、このシングルトン関数を任意のクラスに追加するだけで、クラスごとに1つのインスタンスのみが作成されます。

注:new Class();の使用を排除するために、常に__constructをプライベートにする必要があります。インスタンス化。


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シングルトンクラスのベストプラクティス

やはりシングルトンパターンを使用する必要があると考えている場合は、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

より投票された回答を読んでいる間、私はこのようなことを心に留めていました。幸いにも、それはすでにここにありました:)
ハフ

3

このすべての複雑さ(「レイトスタティックバインディング」... harmph)は、私にとって、PHPの壊れたオブジェクト/クラスモデルの兆候にすぎません。クラスオブジェクトがファーストクラスオブジェクト(Pythonを参照)の場合、「$ _ instance」はクラスインスタンスになります変数になります-のメンバー/プロパティではなく、クラスオブジェクトのメンバーであり、共有オブジェクトでもありその子孫によって。Smalltalkの世界では、これが「クラス変数」と「クラスインスタンス変数」の違いです。

PHPでは、パターンはコードを書くためのガイドであるというガイダンスを心に留める必要があるように見えます-シングルトンテンプレートについて考えるかもしれませんが、実際の「シングルトン」クラスから継承するコードを書こうとしていますPHPを誤解しているように見えます(ただし、私は進取の気のある人が適切なSVNキーワードを作成できると思っていましたが)。

共有テンプレートを使用して、引き続き各シングルトンを個別にコーディングします。

私は絶対にシングルトンの邪悪な議論から離れていることに注意してください、人生は短すぎます。


あなたの発言は、PHP言語のますます複雑化するものを見るときに正しいです。非常に多くの異なるコーディングパラダイムにある非常に多くの異なるデザインホールから抜け出すために、あまりにも多くの新しいキーワードが追加されているようです。さらに悪いことに、変更率が高く、ホストと開発プラットフォーム間でバージョンが異なるため、今日の「solution du jour」(@ Eric Andersonの回答の特徴[ stackoverflow.com/a/23998306/3696363])が機能しない「最新、最高」の代わりに「安定」バージョンを実行している可能性のある本番システム。
Eliyahu Skoczylas

2

これはおそらく不要な炎上戦争を引き起こすだろうことはわかっていますが、複数のデータベース接続がどのように必要になるかはわかるので、シングルトンがそのための最良の解決策ではないかもしれないという点を認めます...しかし、シングルトンパターンの他の用途は、非常に便利です。

ここに例があります:本当に軽量なものが欲しかったので、自分のMVCとテンプレートエンジンをロールすることにしました。ただし、表示したいデータには、≥やμなどの特殊な数学文字がたくさん含まれています。データは、HTMLで事前にエンコードされているのではなく、実際のUTF-8文字としてデータベースに保存されています。私のアプリは、HTMLに加えてPDFやCSVなどの他の形式を配信できます。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
実行時間:シングルトンを使用して27.842966794968秒
実行時間:シングルトンを使用せずに237.78191494942秒

そのため、私は確かに専門家ではありませんが、ある種のデータの低速呼び出しのオーバーヘッドを削減しながら、それを非常にシンプル(必要なことを実行する単一のコード行)にする、より便利で信頼できる方法はありません。私の例では、便利なメソッドが1つしかないため、グローバルに定義された関数に勝るものはありませんが、2つのメソッドがあるとすぐに、それらをグループ化したいと思いますよね?私は基地から離れていますか?

また、チュートリアルを検索するときにいつも目にする「//ここで何か便利なこと」のような例が含まれていると視覚化が難しい場合があるので、実際に何かをする例を好みます。

とにかく、このタイプのものにシングルトンを使用することが不利な(または過度に複雑な)理由についてのフィードバックやコメントが欲しいです。


1

この記事では、トピックをかなり広範囲にカバーしています:http : //www.phptherightway.com/pages/Design-Patterns.html#singleton

次の点に注意してください。

  • コンストラクター__construct()protectednewオペレーターを介してクラス外に新しいインスタンスを作成しないように宣言されています。
  • magicメソッド__clone()privateclone演算子を介したクラスのインスタンスのクローン作成を防ぐために宣言されています。
  • magicメソッド__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

最初の回答に同意しますが、クラスをfinalとして宣言し、シングルトンの拡張がシングルトンパターンに違反するため拡張できないようにします。また、インスタンス変数はプライベートにして、直接アクセスできないようにする必要があります。また、__ 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
シングルトンではないことを除いて。シングルトンクラスの複数のインスタンスを作成できます。
Andrew Moore

シングルトンクラスに影響を与えるインスタンスに関係なく、変更はシングルトンのすべてのインスタンスに対して行われるためです。上記の2つの関数を追加しました。ここで、1つのインスタンスのデータを変更して、他のインスタンスをチェックしてみましょう。それで、それはシングルトンではありませんか?
bboydev

5
シングルトンは、それ自体のインスタンスを1つだけ許可するクラスです。複数のインスタンスを作成すると、その原則が無効になります。
Andrew Moore
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.