Tạo mẫu thiết kế Singleton trong PHP5


204

Làm thế nào một người có thể tạo một lớp Singleton bằng các lớp PHP5?



1
@Andrew Đừng khởi tạo một thể hiện thứ hai kết nối với cơ sở dữ liệu sau đó. Truyền ví dụ đó đến nơi cần thiết. Sự cần thiết cho một Singleton là một mùi Code. Thông tin khác tại gooh.posterous.com/singletons-in-php
Gordon

3
@Amrew Mmmmkay. Không xúc phạm, nhưng tôi khuyên bạn nên lấy một cuốn sách về chất lượng phần mềm trước khi chúng tôi tiếp tục cuộc thảo luận này. Singletons không đơn giản hóa nhưng làm phức tạp việc bảo trì và phát triển bình thường. Trên thực tế, đó là cách khác: đó là các bài kiểm tra đơn vị giúp đơn giản hóa và cho phép phát triển ngay từ đầu.
Gordon

3
@Andrew: Bây giờ bạn giả sử rằng bạn chỉ cần một kết nối cơ sở dữ liệu. Điều gì xảy ra khi yêu cầu của bạn thay đổi và bạn thực sự cần nói chuyện với 2 máy chủ cơ sở dữ liệu? Chưa kể nếu bạn không thể tin tưởng vào nhóm của mình để làm mọi thứ đúng , thì việc tạo ra một singleton sẽ không giúp bạn ít nhất. Làm mọi thứ ngay từ đầu và có được một đội mà bạn có thể tin tưởng và bạn sẽ ổn.
ircmaxell

4
Chỉ vì Singleton đã bị lạm dụng quá mức không làm cho nó trở thành một mô hình xấu nên tránh. Đừng ghét Singleton. Đôi khi nó là một giải pháp hoàn toàn tốt cho một vấn đề nhất định. Tốt hơn nên bắt đầu tranh luận lý do tại sao chúng ta không nên sử dụng nó thay vì chỉ cố gắng làm suy giảm cảm xúc.
Gilles Lesire

Câu trả lời:


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

    }
}

Để sử dụng:

$fact = UserFactory::Instance();
$fact2 = UserFactory::Instance();

$fact == $fact2;

Nhưng:

$fact = new UserFactory()

Ném một lỗi.

Xem http://php.net/manual/en/lingu.variables.scope.php#lingu.variabled.scope.static để hiểu phạm vi biến tĩnh và lý do cài đặt static $inst = null;hoạt động.


59
để so sánh hai trường hợp bạn nên sử dụng === thay vì ==. == sẽ trả về true nếu $ fact1 và $ fact2 đều thuộc cùng một lớp, nhưng === chỉ trả về true nếu cả hai đều là cùng một thể hiện của cùng một đối tượng.
Keith Twombley

10
phương pháp nhân bản cũng nên riêng tư
Alex Petrov

22
Phương thức này có đặt lại phiên bản UserFactory thành null mỗi khi bạn gọi Instance () không? Trong java, biến $ inst sẽ là một thuộc tính tĩnh riêng không nên được đặt lại nhiều lần, nếu không bạn cũng có thể không biến nó thành một singleton.
Rudy Garcia

8
Dưới đây là một ghi tốt lên lý do tại sao và làm thế nào khai báo biến như tĩnh trong chức năng hoạt động như tác giả dự định: php.net/manual/en/...
hereswhatidid

10
Bạn nên sử dụng $ inst = new self (); không phải $ inst = new UserFactory (); cho bất cứ ai đi qua điều này sau +1 để sử dụng một phương pháp được xây dựng trong PHP.
Ligemer

119

PHP 5.3 cho phép tạo ra một lớp Singleton có thể kế thừa thông qua liên kết tĩnh muộn:

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

Điều này giải quyết vấn đề, rằng trước PHP 5.3, bất kỳ lớp nào mở rộng Singleton sẽ tạo ra một thể hiện của lớp cha thay vì lớp của nó.

Bây giờ bạn có thể làm:

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

Và $ foo sẽ là một thể hiện của Foobar thay vì một thể hiện của Singleton.


1
Liên kết tĩnh muộn thực sự là một điều rất tốt trong php 5.3. Quá tệ, tôi vẫn không thể sử dụng nó.
AntonioCS

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

4
Điều này hoàn toàn không hoạt động, thực tế là Foobar là lớp đầu tiên bạn xây dựng?
Chris KL

1
vẫn có khả năng sao chép ..... "$ a = Singleton :: getInstance (); $ b = unserialize (serialize ($ a)); $ a! == $ b;"
bortunac

15
Điều này không hoạt động khi có nhiều hơn một lớp con! $instancecư trú tại Singleton, không phải là lớp con. Sau khi một số lớp con được khởi tạo, getInstance () sẽ trả về thể hiện đó cho tất cả các lớp con.
mpartel

116

Thật không may câu trả lời của Inwdr bị phá vỡ khi có nhiều lớp con.

Đây là một lớp cơ sở Singleton kế thừa chính xác.

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

Mã kiểm tra:

class Foo extends Singleton {}
class Bar extends Singleton {}

echo get_class(Foo::getInstance()) . "\n";
echo get_class(Bar::getInstance()) . "\n";

1
Điều này là gần nhất để thực hiện Singleton chính xác. Bạn cũng nên xem xét việc ném vào phương thức __wakeup () để ngăn chặn không xác định.
Robert Rossmann

Trên thực tế, bạn phải ném Ngoại lệ hoặc đưa ra lỗi theo cách thủ công - khai báo hàm là được bảo vệ / riêng tư sẽ chỉ đưa ra một E_WARNING nói rằng nó không thể truy cập phương thức, nhưng sẽ tiếp tục.
Robert Rossmann

Cảm ơn. Tôi thường có tất cả các cảnh báo, vv biến thành trường hợp ngoại lệ, vì vậy tôi đã quên mất sự khác biệt khi tôi thử nghiệm: P
mpartel

Đây là giải pháp duy nhất tôi thấy rằng giao dịch đúng với nhiều lớp con. Cảm ơn bạn!
Bob Dankert

36

Cách thực sự và hiện đại để tạo mẫu Singleton là:

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

}

Vì vậy, bây giờ bạn có thể sử dụng nó như thế nào.

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

Như bạn thấy nhận thức này linh hoạt hơn rất nhiều.


4
Đây là câu trả lời rõ ràng nhất về mẫu Singleton trong chuỗi này. Cảm ơn.
Gus

Tôi đã thực hiện phương pháp này và nó hoạt động như được phát hiện: trường hợp thứ hai trở thành null. Tuy nhiên tôi cũng không cần phải mở rộng lớp bê tông. Tôi vừa triển khai Singleton :: instance () trong hàm tạo của lớp cụ thể đó.
snaphuman

trong instancechức năng $instancenên nullkhôngfalse
Mifas

Đúng, nhưng nó không hoạt động, mà là phương pháp.
Áp-ra-ham Trifov

26

Bạn có thể nên thêm một phương thức __clone () riêng tư để không cho phép nhân bản một thể hiện.

private function __clone() {}

Nếu bạn không bao gồm phương pháp này, điều sau đây có thể

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

ngay bây giờ $inst1! == $inst2- chúng không còn là ví dụ nữa.


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

sử dụng:

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

nghỉ ngơi

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

Nếu bạn đang sử dụng PHP 5.4: đặc trưng là một tùy chọn, vì vậy bạn không phải lãng phí hệ thống phân cấp thừa kế để có mẫu Singleton

và cũng lưu ý rằng cho dù bạn sử dụng các đặc điểm hay mở rộng lớp Singleton, một kết thúc lỏng lẻo là tạo ra các singleton của các lớp con nếu bạn không thêm dòng mã sau:

   protected static $inst = null;

trong lớp trẻ

kết quả bất ngờ sẽ là:

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

Mã này có thể áp dụng cho bất kỳ lớp nào mà không cần quan tâm đến tên lớp của nó.


8

Hỗ trợ nhiều đối tượng với 1 dòng trên mỗi lớp:

Phương thức này sẽ thực thi các singletons trên bất kỳ lớp nào bạn muốn, vì bạn phải làm là thêm 1 phương thức vào lớp bạn muốn tạo một singleton và điều này sẽ làm điều đó cho bạn.

Điều này cũng lưu trữ các đối tượng trong một lớp "SingleTonBase" để bạn có thể gỡ lỗi tất cả các đối tượng mà bạn đã sử dụng trong hệ thống của mình bằng cách đệ quy các SingleTonBaseđối tượng.


Tạo một tệp có tên SingletonBase.php và đưa nó vào thư mục gốc của tập lệnh của bạn!

Mã là

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

Sau đó, đối với bất kỳ lớp nào bạn muốn tạo một singleton chỉ cần thêm phương thức nhỏ này.

public static function Singleton()
{
    return SingletonBase::Singleton(get_class());
}

Đây là một ví dụ nhỏ:

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

Và bạn chỉ có thể thêm hàm singleton này vào bất kỳ lớp nào bạn có và nó sẽ chỉ tạo 1 thể hiện cho mỗi lớp.

LƯU Ý: Bạn phải luôn đặt __construct ở chế độ riêng tư để loại bỏ việc sử dụng Class mới (); tức thời.


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

Bạn không thực sự cần sử dụng mẫu Singleton vì nó được coi là một mẫu phản. Về cơ bản có rất nhiều lý do để không thực hiện mô hình này. Đọc phần này để bắt đầu: Thực hành tốt nhất trên các lớp đơn PHP .

Nếu sau tất cả, bạn vẫn nghĩ rằng bạn cần sử dụng mẫu Singleton thì chúng tôi có thể viết một lớp cho phép chúng tôi có được chức năng Singleton bằng cách mở rộng lớp trừu tượng SingletonClassVendor của chúng tôi.

Đây là những gì tôi đi kèm để giải quyết vấn đề này.

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

}

Sử dụng ví dụ:

/**
 * 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
    }
}

Chỉ để chứng minh rằng nó hoạt động như mong đợi:

/**
 *  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

Trong khi đọc các câu trả lời nâng cao hơn, tôi có một cái gì đó như thế này trong tâm trí. May mắn là nó đã ở đây :)
ghét

3

Tất cả sự phức tạp này ("liên kết tĩnh muộn" ... harumph), đối với tôi, chỉ đơn giản là một dấu hiệu của mô hình đối tượng / lớp bị hỏng của PHP. Nếu đối tượng lớp là đối tượng hạng nhất (xem Python), sau đó "$ _instance" sẽ là một lớp dụ biến - một thành viên của đối tượng lớp, trái ngược với một thành viên / thuộc tính của các thể hiện của nó và trái ngược với chia sẻ bởi con cháu của nó. Trong thế giới Smalltalk, đây là sự khác biệt giữa "biến lớp" và "biến thể hiện lớp".

Trong PHP, có vẻ như tôi cần phải ghi nhớ hướng dẫn rằng các mẫu là hướng dẫn viết mã - có lẽ chúng ta có thể nghĩ về một mẫu Singleton, nhưng cố gắng viết mã kế thừa từ một lớp "Singleton" thực sự có vẻ sai lầm cho PHP (mặc dù tôi cho rằng một số linh hồn dám nghĩ dám làm có thể tạo ra một từ khóa SVN phù hợp).

Tôi sẽ tiếp tục chỉ mã riêng từng singleton, sử dụng một mẫu được chia sẻ.

Lưu ý rằng tôi hoàn toàn đứng ngoài cuộc thảo luận về những kẻ độc thân, cuộc sống quá ngắn ngủi.


Nhận xét của bạn là đúng khi xem sự phức tạp ngày càng tăng của ngôn ngữ PHP. Có vẻ như có quá nhiều từ khóa mới đang được thêm vào để tìm ra quá nhiều lỗ hổng thiết kế khác nhau trong quá nhiều mô hình mã hóa khác nhau. Tồi tệ hơn, vì tốc độ thay đổi cao và phiên bản bị lệch giữa các máy chủ và nền tảng phát triển, "giải pháp du lịch" ngày nay (giống như các đặc điểm trong câu trả lời của @Eric Anderson [ stackoverflow.com/a/23998306/3696363], ) không hoạt động trên các hệ thống sản xuất có thể đang chạy phiên bản "ổn định" thay vì "mới nhất, lớn nhất".
Eliyahu Skoczylas

2

Tôi biết điều này có thể sẽ gây ra một cuộc chiến nảy lửa không cần thiết, nhưng tôi có thể thấy bạn có thể muốn nhiều hơn một kết nối cơ sở dữ liệu như thế nào, vì vậy tôi sẽ thừa nhận rằng singleton có thể không phải là giải pháp tốt nhất cho điều đó ... tuy nhiên, có sử dụng khác của mẫu singleton mà tôi thấy cực kỳ hữu ích.

Đây là một ví dụ: Tôi quyết định tung công cụ tạo khuôn mẫu và MVC của riêng mình vì tôi muốn thứ gì đó thực sự nhẹ. Tuy nhiên, dữ liệu mà tôi muốn hiển thị chứa rất nhiều ký tự toán học đặc biệt như ≥ và và những gì bạn có ... Dữ liệu được lưu trữ dưới dạng ký tự UTF-8 thực tế trong cơ sở dữ liệu của tôi thay vì được mã hóa trước HTML vì ứng dụng của tôi có thể cung cấp các định dạng khác như PDF và CSV ngoài HTML. Vị trí thích hợp để định dạng cho HTML là bên trong mẫu ("chế độ xem" nếu bạn muốn) chịu trách nhiệm hiển thị phần trang đó (đoạn trích). Tôi muốn chuyển đổi chúng thành các thực thể HTML thích hợp của chúng, nhưng hàm get_html_translation_table () của PHP không phải là siêu nhanh. Nó có ý nghĩa tốt hơn để lấy dữ liệu một lần và lưu trữ dưới dạng một mảng, làm cho nó có sẵn cho tất cả mọi người sử dụng. Đây' sa mẫu tôi gõ cùng nhau để kiểm tra tốc độ. Có lẽ, điều này sẽ hoạt động bất kể các phương thức khác mà bạn sử dụng (sau khi lấy ví dụ) có tĩnh hay không.

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

Về cơ bản, tôi đã thấy kết quả điển hình như thế này:

Kiểm tra php
Thời gian chạy: 27.842966794968 giây bằng singleton
Thời gian chạy: 237.78191494942 giây mà không sử dụng singleton

Vì vậy, trong khi tôi chắc chắn không phải là chuyên gia, tôi không thấy một cách thuận tiện và đáng tin cậy hơn để giảm chi phí của các cuộc gọi chậm đối với một số loại dữ liệu, trong khi làm cho nó cực kỳ đơn giản (một dòng mã để làm những gì bạn cần). Cấp ví dụ của tôi chỉ có một phương thức hữu ích, và do đó không tốt hơn một hàm được xác định toàn cầu, nhưng ngay khi bạn có hai phương thức, bạn sẽ muốn nhóm chúng lại với nhau, phải không? Tôi có cách ra khỏi căn cứ không?

Ngoài ra, tôi thích các ví dụ thực sự LÀM một cái gì đó, vì đôi khi thật khó để hình dung khi một ví dụ bao gồm các câu như "// làm điều gì đó hữu ích ở đây" mà tôi thấy mọi lúc khi tìm kiếm hướng dẫn.

Dù sao, tôi thích bất kỳ phản hồi hoặc nhận xét nào về lý do tại sao sử dụng một singleton cho loại điều này là bất lợi (hoặc quá phức tạp).


1

Bài viết này bao gồm chủ đề khá rộng rãi: http://www.phptherightway.com/pages/Design-Potypes.html#singleton

Lưu ý những điều dưới đây:

  • Hàm tạo __construct()được khai báo là protectedđể ngăn việc tạo một thể hiện mới bên ngoài lớp thông qua newtoán tử.
  • Phương thức ma thuật __clone()được tuyên bố là privateđể ngăn chặn việc sao chép một thể hiện của lớp thông qua clonetoán tử.
  • Phương thức ma thuật __wakeup()được khai báo là privateđể ngăn chặn việc hủy kích hoạt một thể hiện của lớp thông qua hàm toàn cục unserialize().
  • Một phiên bản mới được tạo thông qua liên kết tĩnh muộn trong phương thức tạo tĩnh getInstance()với từ khóa static. Điều này cho phép phân lớp của class Singletonví dụ.

1

Tôi đã viết từ lâu đã nghĩ để chia sẻ ở đây

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

Tôi đồng ý với câu trả lời đầu tiên nhưng tôi cũng sẽ tuyên bố lớp là cuối cùng để nó không thể được mở rộng vì việc mở rộng một singleton vi phạm mẫu đơn. Ngoài ra biến cá thể phải ở chế độ riêng tư để không thể truy cập trực tiếp. Đồng thời đặt phương thức __clone ở chế độ riêng tư để bạn không thể sao chép đối tượng singleton.

Dưới đây là một số mã ví dụ.

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

Cách sử dụng ví dụ

$user_factory = UserFactory::getInstance();

Điều này ngăn bạn làm gì (điều này sẽ vi phạm mẫu đơn ..

BẠN KHÔNG THỂ LÀM ĐIỀU NÀY!

$user_factory = UserFactory::$_instance;

class SecondUserFactory extends UserFactory { }

0

Đây phải là cách đúng đắn của Singleton.

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

Tôi thích phương pháp @ jose-segura sử dụng các đặc điểm nhưng không thích xác định một biến tĩnh trên các lớp con. Dưới đây là một giải pháp tránh nó bằng cách lưu trữ các thể hiện trong một biến cục bộ tĩnh cho phương thức nhà máy được lập chỉ mục theo tên lớp:

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

Cách sử dụng giống như @ jose-segura chỉ không cần biến tĩnh trong các lớp con.


0

Lớp cơ sở dữ liệu kiểm tra nếu có bất kỳ trường hợp cơ sở dữ liệu hiện có nào, nó sẽ trả về thể hiện trước đó.

   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] 

*/  

Tham khảo http://www.phptechi.com/php-singleton-design-potypes-example.html


0

Đây là ví dụ về tạo singleton trên lớp Cơ sở dữ liệu

mẫu thiết kế 1) singleton

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

sau đó đưa ra là -

  object(Database)[1]
  object(Database)[1]
  object(Database)[1]

chỉ sử dụng một thể hiện duy nhất không tạo ra 3 thể hiện


0

Ví dụ nhanh:

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

Mong mọi người giúp đỡ.


-4

Đây là ví dụ của tôi cung cấp khả năng gọi là $ var = new Singleton () và cũng tạo 3 biến để kiểm tra nếu nó tạo đối tượng mới:

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
Ngoại trừ việc nó không phải là một singleton. Bạn có thể tạo nhiều phiên bản của lớp Singleton.
Andrew Moore

Tôi nghĩ rằng đó là tất cả, bởi vì bất kể trường hợp nào ảnh hưởng đến lớp Singleton, các thay đổi đều dành cho tất cả các phiên bản của Singleton. Tôi đã thêm hai chức năng ở trên. Bây giờ, hãy thử sửa đổi dữ liệu trong một trường hợp và kiểm tra những người khác. Vì vậy, không phải là Singleton và nếu không - điều gì là không chính xác?
bboydev

5
Một singleton là một lớp chỉ cho phép một thể hiện của chính nó. Bằng cách tạo nhiều trường hợp, bạn đang làm mất hiệu lực của nguyên tắc đó.
Andrew Moore
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.