单例模式的实现和应用示例

<?php
declare(strict_types=1);
ini_set('display_errors', 'On');
error_reporting(-1);

/**
 * PDOi类(单例模式)
 */
class PDOi
{
    private static ?PDOi $instance = null;

    /**
     * 将构造方法声明为private防止通过“new PDOi()”创建实例
     */
    private function __construct()
    {
    }

    /**
     * 将克隆方法声明为private防止复制实例
     */
    private function __clone()
    {
    }

    /**
     * 获取PDOi实例(单例)
     *
     * @return PDOi PDOi实例(单例)
     */
    public static function getInstance(): PDOi
    {
        if (self::$instance === null) {
            echo '[new]PDOi实例成功' . PHP_EOL;
            self::$instance = new self();
        }

        echo '[get]PDOi实例成功' . PHP_EOL;
        return self::$instance;
    }
}

$instance1 = PDOi::getInstance();
$instance2 = PDOi::getInstance();
$instance3 = PDOi::getInstance();
$instance4 = PDOi::getInstance();
$instance5 = PDOi::getInstance();
// [new]PDOi实例成功
// [get]PDOi实例成功
// [get]PDOi实例成功
// [get]PDOi实例成功
// [get]PDOi实例成功
// [get]PDOi实例成功
// 从输出结果可以清楚地看到,虽然五次获取实例,但是只执行了一次实例化操作。


//========== 总结 ==========//
// 1、实现单例模式要点有四个:
//    ① 将构造方法 __construct() 声明为 private 禁止使用 new 关键字创建实例;
//    ② 将克隆方法 __clone() 声明为 private 禁止克隆实例;
//    ③ 定义一个名为 $instance 的 private static 属性,用于保存唯一的实例;
//    ④ 定义一个名为 getInstance() 的 public static 方法,用于获取(唯一的)实例。



下面是单例模式的应用示例:

<?php
declare(strict_types=1);
ini_set('display_errors', 'On');
error_reporting(-1);

$driver   = 'mysql';     // 数据库驱动
$host     = 'localhost'; // 主机地址
$dbname   = 'test_db';   // 数据库名
$port     = 3306;        // 服务端口号
$charset  = 'utf8mb4';   // 字符编码
$username = 'zhangsan';  // 账号
$password = 'pwd-1234';  // 密码

/**
 * PDOi类(单例模式)
 */
class PDOi
{
    private ?PDO $pdo = null; // PDO类实例(该属性声不声明为static均可)

    private static ?PDOi $instance = null; // PDOi类实例(该属性必须声明为static)

    /**
     * 将构造方法声明为private防止通过“new PDOi()”创建实例
     */
    private function __construct()
    {
    }

    /**
     * 将克隆方法声明为private防止复制实例
     */
    private function __clone()
    {
    }

    /**
     * 获取PDOi实例(单例)
     *
     * @return PDOi PDOi实例(单例)
     */
    private static function getInstance(): PDOi
    {
        if (self::$instance === null) {
            self::$instance = new self();

            global $driver;
            global $host;
            global $dbname;
            global $port;
            global $charset;
            global $username;
            global $password;

            // 构造数据源名称(Data Source Name)字符串
            $dsn = "$driver:";
            $dsn .= "host=$host;";
            $dsn .= "dbname=$dbname;";
            $dsn .= "port=$port;";
            $dsn .= "charset=$charset;";

            // PDO连接选项
            $options = [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES $charset",
                PDO::ATTR_EMULATE_PREPARES => false,
            ];

            // 创建PDO类实例
            try {
                self::$instance->pdo = new PDO($dsn, $username, $password, $options);
            } catch (PDOException $e) {
                exit('创建PDO类实例失败:' . $e->getMessage());
            }
        }

        return self::$instance;
    }

    /**
     * 执行语句
     *
     * @param string $query SQL语句
     * @param array $params 参数
     * @return PDOStatement|false 执行成功返回PDOStatement实例,否则返回false
     */
    public static function execute(string $query, array $params = []): PDOStatement|false
    {
        // 预处理要执行的语句
        try {
            $sth = self::getInstance()->pdo->prepare($query);
        } catch (PDOException) {
            $sth = false;
        }

        // 绑定参数
        if ($sth instanceof PDOStatement) {
            foreach ($params as $field => $value) {
                try {
                    $sth->bindValue(":$field", $value);
                } catch (PDOException) {
                    $sth = false;
                    break; // 有一个参数绑定失败,后面的参数已经没有绑定的必要了
                }
            }
        }

        // 执行语句
        if ($sth instanceof PDOStatement && $sth->execute() === false) {
            $sth = false;
        }

        return $sth;
    }
}


$query = 'SELECT * FROM `prefix_user` WHERE `uid` = :uid LIMIT 1';
$params = ['uid' => 9527];

$sth = PDOi::execute($query, $params);
if ($sth instanceof PDOStatement) {
    $fetchAll = $sth->fetchAll();
    $row = $fetchAll[0] ?? [];
    if ($row) {
        echo "俺叫{$row['name']}{$row['gender']}),今年{$row['age']}岁。" . PHP_EOL; // 俺叫张三(男),今年18岁。
    }
}

Copyright © 2024 码农人生. All Rights Reserved