Nasıl bir PHP5 sınıflarını kullanarak bir Singleton sınıf oluşturmak istiyorsunuz?
/**
* 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 instance it
*
*/
private function __construct()
{
}
}
Kullanmak için:
$fact = UserFactory::Instance();
$fact2 = UserFactory::Instance();
$ Gerçektir == $ fact2;
Ancak:
$fact = new UserFactory()
Bir hata atar
PHP 5.3 bağlama geç statik yoluyla kalıtsal Singleton sınıfının oluşturulmasını sağlar:
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;
}
}
Bu önceki PHP 5.3 bir Singleton genişletilmiş herhangi bir sınıf yerine, kendi üst sınıfının bir örneğini üretmek olacağını, sorunu çözer.
Şimdi yapabilirsiniz:
class Foobar extends Singleton {};
$foo = Foobar::getInstance();
Ve $ foo Filanca bir örneği yerine Singleton bir örneği olacaktır.
Muhtemelen bir örneğinin klonlama izin vermemek için özel bir __ clone () yöntemini eklemek gerekir.
private function __clone() {}
Bu yöntemi dahil etmezseniz şu muhtemel alır
$inst1=UserFactory::Instance(); // to stick with the example provided above
$inst2=clone $inst1;
şimdi $inst1
== $inst2
- onlar bir daha aynı örneği değildir.
Birden çok alt sınıfları vardır yazık ki Inwdr's answer sonları.
Burada doğru bir soydan Singleton temel sınıftır.
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];
}
}
Test kodu:
class Foo extends Singleton {}
class Bar extends Singleton {}
echo get_class(Foo::getInstance()) . "\n";
echo get_class(Bar::getInstance()) . "\n";
<?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(){
}
}
kullanmak için:
/**
* 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 kullanıyorsanız: trait its an option, so you don't have to waste the inheritance hierarchy in order to have the Singleton pattern strong>
and also notice that whether you use traits or extends Singleton class one loose end was to create singleton of child classes if you dont add the following line of code:
protected static $inst = null;
alt sınıfta
beklenmedik sonucu olacaktır:
object(DBFactoryChild)#1 (0) {
}
object(DBFactoryChild)#1 (0) {
}
O "bunu yapmayın" demek doğru cevap olabilir. Ilgili soruya bakın What is so bad about Singletons. Orada ilgili makalelere bazı iyi bağlantıları vardır.
Bu yöntem, istediğiniz herhangi bir sınıf singletons zorlamak olacak, yapmanız gereken al bir singleton'ununu yapmak isteyen ve bu sizin için yapacak sınıfına 1 yöntemini eklemektir.
Eğer SingleTonBase
nesneleri recusing tarafından sisteminizde kullandığınız tüm nesneleri ayıklama böylece Bu aynı zamanda bir "SingleTonBase" sınıfında nesneleri saklar.
SingletonBase.php adında bir dosya oluşturun ve komut kök içinde yer alıyor!
Kodudur
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;
}
}
Sonra herhangi bir sınıf için bir singleton sadece bu küçük tek yöntem eklemek yapmak istiyorum.
public static function Singleton()
{
return SingletonBase::Singleton(get_class());
}
İşte küçük bir örnek:
include 'libraries/SingletonBase.resource.php';
class Database
{
//Add that singleton funtion.
public static function Singleton()
{
return SingletonBase::Singleton(get_class());
}
public function run()
{
echo 'running...';
}
}
$Database = Database::Singleton();
$Database->run();
Ve sadece sahip olduğunuz herhangi bir sınıfta bu tekil işlev ekleyebilir ve sadece sınıf başına 1 örneğini oluşturur.
NOT: Her zaman __ yeni Sınıf kullanımını ortadan kaldırmak için özel yapı () yapmak gerekir; örneklemi.
Bu muhtemelen gereksiz bir alev savaşa neden olacak biliyorum, ama ben birden fazla veritabanı bağlantısı isteyebilirsiniz nasıl görebilirsiniz, bu yüzden tekiz bunun için en iyi çözüm olmayabilir noktayı kabullenmek olurdu ... ancak diğer vardır Ben son derece yararlı buluyorum tekiz desen kullanır.
İşte bir örnek: Ben gerçekten hafif bir şey istedim becuase kendi MVC ve çiftleşmiş motoru rulo karar verdi. Ancak, görüntülemek istediğiniz veriler, ≥ gibi özel matematik karakterleri bir sürü içerir ve μ benim app HTML ek olarak PDF ve CSV gibi diğer formatları teslim edebilir çünkü ve sen ... veri, benim veritabanında ziyade ön-html kodlanmış gerçek UTF-8 karakter olarak saklanır mı var. O sayfa bölümü (pasajı) dönüştürülmesinden sorumlu olan HTML biçimlendirmek için uygun yer şablon içinde (siz eğer "view") 'dir. Ben onların uygun HTML kuruluşlara onları dönüştürmek istiyorsanız, ancak PHPs get_html_translation_table () fonksiyonu süper hızlı değildir. Bu veriler bir defa almak ve bir dizi olarak depolamak, kullanmak için tüm kullanılabilir hale getirmek daha mantıklı. İşte hızını test etmek için birlikte çaldı bir örnek. Muhtemelen bu ne olursa olsun (örneğini aldıktan sonra) kullandığınız diğer yöntemler veya statik olup olmadığı çalışacak.
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";
Temelde, ben bu gibi tipik sonuçlar gördüm:
php test.php Run time: 27.842966794968 seconds using singleton Run time: 237.78191494942 seconds without using singleton
Ben kesinlikle hiçbir uzman değilim iken süper basit (ne gerek yapmak için tek satır kod) yaparken Yani, ben, verilerin çeşit yavaş aramaların yükünü azaltmak için daha uygun ve güvenilir bir yol görmüyorum. Verilen benim örnek tek bir kullanışlı yöntemi vardır ve bu nedenle global tanımlanmış fonksiyonun daha iyi olduğu, ancak en kısa sürede iki yöntem var gibi, doğru, grup birlikte onları istediğiniz gidiyoruz? Ben kapalı bir şekilde baz mıyım?
Bazen bir örnek öğreticiler ararken ben her zaman görmek "/ / Burada yararlı bir şeyler yapmak" gibi ifadeler içerdiği zaman görselleştirmek zor beri Ayrıca, ben, aslında bir şey DO örneklerini tercih ederim.
Her neyse, ben bu tür bir şey için tekiz kullanarak zararlı (ya da aşırı karmaşık) neden üzerinde herhangi bir geri bildirim ya da yorum isterim.
Tüm bu karmaşıklık ("geç statik bağlama" ... harumph), bana, PHP'nin kırık nesne / sınıf modeli sadece bir işaretidir. Sınıf nesnesinin bir üyesi, onun örneklerinin üyesi / özellik aksine, - sınıf nesneleri birinci sınıf nesneleri (Python bakınız) olsaydı, o zaman "$ _instance" bir sınıf instance değişken olacaktır ve aynı zamanda torunları tarafından paylaşılan karşı. Smalltalk dünyasında, bu bir "sınıf değişkeni" ve "sınıf örneği değişkeni" arasındaki farktır.
PHP, biz kalp desenleri kod yazma yönelik bir kılavuz rehberlik almak gerekir gibi görünüyor bana - belki bir Singleton şablonu hakkında düşünebilirsiniz, ama gerçek bir "Singleton" sınıfından miras kod yazmaya çalışıyorum (Ben bazı girişimci ruh, uygun bir SVN anahtar kelime oluşturabilirsiniz gerekiyordu ama) PHP için yanlış görünüyor.
Paylaşılan bir şablonu kullanarak, sadece ayrı ayrı singleton'ununu kod devam edecektir.
Ben kesinlikle tekil-olan-kötü tartışma OUT kalıyorum dikkat edin, hayat çok kısa.
Ben ilk yanıt katılıyorum ama singleton deseni ihlal singleton'ununu uzanan olarak uzatılabilir değil böylece ben de nihai olarak sınıf bildirmek istiyorum. Doğrudan erişemez böylece Ayrıca örnek değişken özel olmalıdır. Eğer tek nesne klon değil böylece Ayrıca __ klon yöntemi özel yapmak.
Aşağıda bazı örnek kod.
/**
* 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;
}
}
Örnek
$user_factory = UserFactory::getInstance();
Bu singleton deseni ihlal edecek (yapmaktan durur ne ..
YOU CANNOT DO THIS!
$user_factory = UserFactory::$_instance;
class SecondUserFactory extends UserFactory { }
Bu Singleton doğru yol olmalıdır.
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(){
}
}
Burada $ var olarak aramak için yeteneği sağlar benim örnek = new Singleton () ve aynı zamanda yeni bir nesne oluşturur olmadığını test etmek için 3 değişken oluşturma:
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();