如何使用PHP5类创建单例类?
当前回答
下面是我的例子,它提供了调用as $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();
其他回答
这应该是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(){
}
}
支持多对象,每类一行:
这个方法将在你想要的任何类上强制单例,你所要做的就是向你想要创建单例的类中添加一个方法,这个方法会为你做这件事。
这也将对象存储在“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();
你可以在任何类中添加这个单例函数,每个类只创建一个实例。
注意:你应该始终将__construct设为private以消除new Class()的使用;实例化。
不幸的是,当有多个子类时,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";
/**
* Singleton class
*
*/
final class UserFactory
{
private static $inst = null;
// Prevent cloning and de-serializing
private function __clone(){}
private function __wakeup(){}
/**
* Call this method to get singleton
*
* @return UserFactory
*/
public static function Instance()
{
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;
But:
$fact = new UserFactory()
抛出错误。
参见http://php.net/manual/en/language.variables.scope.php#language.variables.scope.static了解静态变量的作用域以及为什么设置static $inst = null;的工作原理。
我知道这可能会引起不必要的争论,但是我知道您可能需要多个数据库连接,所以我承认单例可能不是最好的解决方案……然而,我发现单例模式还有其他非常有用的用途。
Here's an example: I decided to roll my own MVC and templating engine because I wanted something really lightweight. However, the data that I want to display contains a lot of special math characters such as ≥ and μ and what have you... The data is stored as the actual UTF-8 character in my database rather than pre-HTML-encoded because my app can deliver other formats such as PDF and CSV in addition to HTML. The appropriate place to format for HTML is inside the template ("view" if you will) that is responsible for rendering that page section (snippet). I want to convert them to their appropriate HTML entities, but PHPs get_html_translation_table() function is not super fast. It makes better sense to retrieve the data one time and store as an array, making it available for all to use. Here's a sample I knocked together to test the speed. Presumably, this would work regardless of whether the other methods you use (after getting the instance) were static or not.
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 Run time: 27.842966794968 seconds using singleton Run time: 237.78191494942 seconds without using singleton
因此,虽然我不是专家,但我认为没有更方便、更可靠的方法来减少对某些数据的缓慢调用的开销,同时使其超级简单(只需一行代码就可以完成所需的工作)。假设我的例子只有一个有用的方法,因此并不比一个全局定义的函数好,但是一旦你有了两个方法,你就想把它们组合在一起,对吗?我是不是太离谱了?
此外,我更喜欢真正做一些事情的例子,因为有时很难想象一个例子中包含“//在这里做一些有用的事情”这样的语句,这是我在搜索教程时经常看到的。
无论如何,我希望有任何关于为什么在这种情况下使用单例是有害的(或过于复杂)的反馈或评论。
推荐文章
- 如何在PHP中截断字符串最接近于一定数量的字符?
- PHP错误:“zip扩展名和unzip命令都没有,跳过。”
- Nginx提供下载。php文件,而不是执行它们
- Json_encode()转义正斜杠
- 如何在PHP中捕获cURL错误
- 模板方法和策略模式之间的区别是什么?
- 如何要求一个分叉与作曲家?
- MVC中的业务逻辑
- 如何在php中创建可选参数?
- 如何在Kotlin中实现生成器模式?
- 在文本文件中创建或写入/追加
- 为什么PHP的json_encode函数转换UTF-8字符串为十六进制实体?
- 如何从一个查询插入多行使用雄辩/流利
- 工厂模式和策略模式之间的区别是什么?
- 在PHP单元测试执行期间,如何在CLI中输出?