Jadual Kandungan
回复内容:
单例模式是指整个应用中类只有一个对象实例的设计模式。
Rumah pembangunan bahagian belakang tutorial php 设计模式 - 关于PHP单例模式,有一点不明白,求指教!

设计模式 - 关于PHP单例模式,有一点不明白,求指教!

Jun 06, 2016 pm 08:25 PM
php Singleton corak reka bentuk

首先,我定义个类,实现单例模式:(这里是简单一写,就是个最基本的单例)

<code>class Demo
{
    public static $instance;
    
    private function __Construct()
    {
        //TODO
    }
    
    public static function getInstance()
    {
        if(!self::$instance){
            self::$instance = new static();
        }
        
        return self::$instance;
    }
    
    public function call()
    {
        //其他方法
    }
}</code>
Salin selepas log masuk
Salin selepas log masuk

下面有两种方式实例化类:

1.在需要用的地方

<code>$aa = Demo::getInstance();
$bb = Demo::getInstance();
$cc = Demo::getInstance();</code>
Salin selepas log masuk
Salin selepas log masuk

这样调用肯定是没问题的,一般情况也是这样初始化。

2.定义一个普通类,写个函数初始化,保存在一个静态变量,如下:

类:

<code>class Demo{
    public function __Construct(){
        //TODO
    }
}</code>
Salin selepas log masuk
Salin selepas log masuk

函数:

<code>function get_obj(){
    static $obj;
    if($obj){
        return $obj;
    }else{
        $obj = new Demo;
        return $obj;
    }
}</code>
Salin selepas log masuk
Salin selepas log masuk

在需要调用的地方这样写:

<code>$obj = get_obj();
$obj->call();

$obj2 = get_obj();
$obj2->call();

$obj3 = get_obj();
$obj3 = get_obj();</code>
Salin selepas log masuk
Salin selepas log masuk

这样不是也只实例化一次这个类吗?

回复内容:

首先,我定义个类,实现单例模式:(这里是简单一写,就是个最基本的单例)

<code>class Demo
{
    public static $instance;
    
    private function __Construct()
    {
        //TODO
    }
    
    public static function getInstance()
    {
        if(!self::$instance){
            self::$instance = new static();
        }
        
        return self::$instance;
    }
    
    public function call()
    {
        //其他方法
    }
}</code>
Salin selepas log masuk
Salin selepas log masuk

下面有两种方式实例化类:

1.在需要用的地方

<code>$aa = Demo::getInstance();
$bb = Demo::getInstance();
$cc = Demo::getInstance();</code>
Salin selepas log masuk
Salin selepas log masuk

这样调用肯定是没问题的,一般情况也是这样初始化。

2.定义一个普通类,写个函数初始化,保存在一个静态变量,如下:

类:

<code>class Demo{
    public function __Construct(){
        //TODO
    }
}</code>
Salin selepas log masuk
Salin selepas log masuk

函数:

<code>function get_obj(){
    static $obj;
    if($obj){
        return $obj;
    }else{
        $obj = new Demo;
        return $obj;
    }
}</code>
Salin selepas log masuk
Salin selepas log masuk

在需要调用的地方这样写:

<code>$obj = get_obj();
$obj->call();

$obj2 = get_obj();
$obj2->call();

$obj3 = get_obj();
$obj3 = get_obj();</code>
Salin selepas log masuk
Salin selepas log masuk

这样不是也只实例化一次这个类吗?

完善的单例应该是这样的

class Foobar {
    static private $instance;
    
    // 禁止外部new Foobar
    private function __construct() {
    }
    
    // 禁止clone $foobar
    private function __clone() {
    }
    
    static public function getInstance() {
        retrun self::$instance
            ?: (self::$instance = new self);
    }
}
Salin selepas log masuk

如果还要考虑到继承的话

class Foo {
    static private $instances = [];

    protected function __construct() {
    }

    final private function __clone() {
    }

    final static public function getInstance() {
        $class = get_called_class();

        if (!isset(self::$instances[$class])) {
            self::$instances[$class] = new static;
        }

        return self::$instances[$class];
    }
}

class Bar extends Foo {

}

$foo = Foo::getInstance();
$bar = Bar::getInstance();
Salin selepas log masuk

get_obj()那种写法,也可以达到目的,但无法禁止new和clone,也就无法做到真正的单例

这问题我也有印象,我也答过一次
http://segmentfault.com/q/1010000003894638
看了一下还是题主你,为毛要问两遍……

然后你的第二种方式并非单例,请不要陷入抠概念的误区
偶尔也有你这种用法的,少见,并且不好。在一般情况下用一个特定对象就行了,特殊情况下需要新的实例的场合会用,但一般也不会这么写(早期的PHP会有一些类这么做)

= = 所以呢?
两种写法而已啊。。。
另外,你无论怎么看,都还是第一种更清晰,更独立,更好用啊。。。
第一种封装、抽象的更好,更加符合面向对象啊。
存一个静态变量或者另外弄个函数什么的,你不觉得乱嘛。。。

静态变量可以定义在函数里或者类属性,两种写法都可以,但前者封装性会比较好些。

楼主给了我启发,过程式编程中,在全局函数内用静态变量存储数据库连接实现单例:

<code><?php
// config.php
$app = array(
    'db_host'        => '127.0.0.1',
    'db_username'    => 'root',
    'db_password'    => '',
    'db_name'        => 'mysql'
);
// functions.php
function cn_db() {
    global $app;
    static $mysqli;
    if ($mysqli) {
        return $mysqli;
    } else {
        $mysqli = new mysqli($app['db_host'], $app['db_username'], $app['db_password'], $app['db_name']);
        return $mysqli;
    }
}
function cn_foo1() {
    $mysqli = cn_db();
    return $mysqli->query('select user,host from user where user = \'root\'')->fetch_all();
}
function cn_foo2() {
    $mysqli = cn_db();
    return $mysqli->query('select user,host from user')->fetch_all();
}
// controller + view
print_r(cn_foo1());
print_r(cn_foo2());</code>
Salin selepas log masuk

$instance = new static(); (楼主这行代码写错了),感觉单例模式就是个思想,你第一个例子就是面向对象,第二个例子既有面向对象,又有面向过程。

单例模式是指整个应用中类只有一个对象实例的设计模式。

第二种方式是单例吗?

<code>class Demo {
    public function __construct(){
        //TODO
    }
}
function get_obj() {
    static $obj;
    if($obj){
        return $obj;
    }else{
        $obj = new Demo;
        return $obj;
    }
}

var_dump(get_obj());
var_dump(new Demo);
</code>
Salin selepas log masuk

得出的是2个不同的实例

你那样写不符合面向对象思想的,而且你的单例模式也不完整,没有考虑到clone和extends的情况。可以参考下http://www.xtwind.com/design-pattern-singleton.html

单例模式,是一种设计思想实现方式

单例首先是面向对象里面的概念,
第二种就不是面向对象

get_obj()那种写法无法保证外部不new Demo对象

单例的要义第一:私有化构造方法,当然PHP还提供了clone魔术方法,也要私有化。这样做事为了保证外部实例化对象的入口只有一个,只能是我们暴露出来的静态函数getInstance()

单例模式,三私一公,其中的三私:构造方法,克隆魔术方法,实例化对象。一公:对外提供的方法

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Artikel Panas

R.E.P.O. Kristal tenaga dijelaskan dan apa yang mereka lakukan (kristal kuning)
3 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Tetapan grafik terbaik
3 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Cara Memperbaiki Audio Jika anda tidak dapat mendengar sesiapa
3 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Cara Membuka Segala -galanya Di Myrise
3 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Panduan Pemasangan dan Naik Taraf PHP 8.4 untuk Ubuntu dan Debian Panduan Pemasangan dan Naik Taraf PHP 8.4 untuk Ubuntu dan Debian Dec 24, 2024 pm 04:42 PM

PHP 8.4 membawa beberapa ciri baharu, peningkatan keselamatan dan peningkatan prestasi dengan jumlah penamatan dan penyingkiran ciri yang sihat. Panduan ini menerangkan cara memasang PHP 8.4 atau naik taraf kepada PHP 8.4 pada Ubuntu, Debian, atau terbitan mereka

Tarikh dan Masa CakePHP Tarikh dan Masa CakePHP Sep 10, 2024 pm 05:27 PM

Untuk bekerja dengan tarikh dan masa dalam cakephp4, kami akan menggunakan kelas FrozenTime yang tersedia.

Bincangkan CakePHP Bincangkan CakePHP Sep 10, 2024 pm 05:28 PM

CakePHP ialah rangka kerja sumber terbuka untuk PHP. Ia bertujuan untuk menjadikan pembangunan, penggunaan dan penyelenggaraan aplikasi lebih mudah. CakePHP adalah berdasarkan seni bina seperti MVC yang berkuasa dan mudah difahami. Model, Pandangan dan Pengawal gu

Muat naik Fail CakePHP Muat naik Fail CakePHP Sep 10, 2024 pm 05:27 PM

Untuk mengusahakan muat naik fail, kami akan menggunakan pembantu borang. Di sini, adalah contoh untuk muat naik fail.

Pengesah Mencipta CakePHP Pengesah Mencipta CakePHP Sep 10, 2024 pm 05:26 PM

Pengesah boleh dibuat dengan menambah dua baris berikut dalam pengawal.

Pembalakan CakePHP Pembalakan CakePHP Sep 10, 2024 pm 05:26 PM

Log masuk CakePHP adalah tugas yang sangat mudah. Anda hanya perlu menggunakan satu fungsi. Anda boleh log ralat, pengecualian, aktiviti pengguna, tindakan yang diambil oleh pengguna, untuk sebarang proses latar belakang seperti cronjob. Mengelog data dalam CakePHP adalah mudah. Fungsi log() disediakan

Cara Menyediakan Kod Visual Studio (Kod VS) untuk Pembangunan PHP Cara Menyediakan Kod Visual Studio (Kod VS) untuk Pembangunan PHP Dec 20, 2024 am 11:31 AM

Kod Visual Studio, juga dikenali sebagai Kod VS, ialah editor kod sumber percuma — atau persekitaran pembangunan bersepadu (IDE) — tersedia untuk semua sistem pengendalian utama. Dengan koleksi sambungan yang besar untuk banyak bahasa pengaturcaraan, Kod VS boleh menjadi c

Panduan Ringkas CakePHP Panduan Ringkas CakePHP Sep 10, 2024 pm 05:27 PM

CakePHP ialah rangka kerja MVC sumber terbuka. Ia menjadikan pembangunan, penggunaan dan penyelenggaraan aplikasi lebih mudah. CakePHP mempunyai beberapa perpustakaan untuk mengurangkan beban tugas yang paling biasa.

See all articles