PHP 单例模式(php单例模式和工厂模式)
moboyou 2025-07-23 17:57 2 浏览
单例模式(Singleton Pattern)
单例模式(Singleton Pattern):顾名思义, 就是只有一个实例。作为对象的创建模式, 单例模式确保某一个类只有一个实例, 而且自行实例化并向整个系统提供这个实例。
(一)为什么要使用PHP单例模式
1, PHP的应用主要在于数据库应用, 一个应用中会存在大量的数据库操作, 在使用面向对象的方式开发时, 如果使用单例模式, 则可以避免大量的new 操作消耗的资源,
还可以减少数据库连接这样就不容易出现 too many connections情况。
2, 如果系统中需要有一个类来全局控制某些配置信息, 那么使用单例模式可以很方便的实现。 这个可以参看zend Framework的FrontController部分。
3, 在一次页面请求中, 便于进行调试, 因为所有的代码(例如数据库操作类db)都集中在一个类中, 我们可以在类中设置钩子, 输出日志, 从而避免到处var_dump, echo
单例模式的实现
1, 私有化一个属性用于存放唯一的一个实例
2, 私有化构造方法, 私有化克隆方法, 用来创建并只允许创建一个实例
3, 公有化静态方法, 用于向系统提供这个实例
<?php
class Singleton{
//存放实例
private static $_instance = null;
//私有化构造方法、
private function __construct(){
echo "单例模式的实例被构造了";
}
//私有化克隆方法
private function __clone(){
}
//公有化获取实例方法
public static function getInstance(){
if (!(self::$_instance instanceof Singleton)){
self::$_instance = new Singleton();
}
return self::$_instance;
}
}
$singleton=Singleton::getInstance();
?>
<?php
class Single {
/**
* @var Object 保存类实例的静态成员变量
*/
private static $_instance;
/**
* Single constructor. 私有的构造方法
*/
private function __construct(){
echo 'This is a Constructed method;';
}
/**
* @purpose: 创建__clone方法防止对象被复制克隆
*/
public function __clone(){
//E_USER_ERROR只能通过trigger_error($msg, E_USER_ERROR)手动触发。E_USER_ERROR是用户自定义错误类型,可以被set_error_handler错误处理函数捕获,允许程序继续运行。E_ERROR是系统错误,不能被set_error_handler错误处理函数捕获,程序会退出运行
trigger_error('Clone is not allow!',E_USER_ERROR);
}
/**
* @return Single|Object 单例方法,用于访问实例的公共的静态方法
*/
public static function getInstance(){
if(!(self::$_instance instanceof self)){
self::$_instance = new self;
}
return self::$_instance;
}
/**
* @purpose: 测试方法
*/
public function test(){
echo '调用方法成功';
}
}
?>
优点:因为静态方法可以在全局范围内被访问, 当我们需要一个单例模式的对象时, 只需调用getInstance方法, 获取先前实例化的对象, 无需重新实例化。
(二)使用Trait关键字实现类似于继承单例类的功能
Trait Singleton{
//存放实例
private static $_instance = null;
//私有化克隆方法
private function __clone(){
}
//公有化获取实例方法
public static function getInstance(){
$class = __CLASS__;
if (!(self::$_instance instanceof $class)){
self::$_instance = new $class();
}
return self::$_instance;
}
}
class DB {
private function __construct(){
echo __CLASS__.PHP_EOL;
}
}
class DBhandle extends DB {
use Singleton;
private function __construct(){
echo "单例模式的实例被构造了";
}
}
$handle=DBhandle::getInstance();
//注意若父类方法为public,则子类只能为pubic,若父类为private,子类为public ,protected,private都可以。
自 PHP 5.4.0 起, PHP 实现了代码复用的一个方法, 称为 traits。
Traits 是一种为类似 PHP 的单继承语言而准备的代码复用机制。Trait 为了减少单继承语言的限制, 使开发人员能够自由地在不同层次结构内独立的类中复用方法集。
Traits 和类组合的语义是定义了一种方式来减少复杂性, 避免传统多继承和混入类(Mixin)相关的典型问题。
补充, 大多数书籍介绍单例模式, 都会讲三私一公, 公优化静态方法作为提供对象的接口, 私有属性用于存放唯一一个单例对象。私有化构造方法, 私有化克隆方法保证只存在一个单例。
但实际上, 虽然我们无法通过 new 关键字和clone出一个新的对象, 但我们若想得到一个新对象。
还是有办法的, 那就是通过序列化和反序列化得到一个对象。私有化sleep()和wakeup()方法依然无法阻止通过这种方法得到一个新对象。
或许真得要阻止, 你只能去__wakeup添加删除一个实例的代码, 保证反序列化增加一个对象, 你就删除一个。不过这样貌似有点怪异。
(三) PHP单例模式及应用场景
单例模式在数据库链接中的使用:
<?php
class Mysql
{
// MYSQL数据库连接信息
const HOSTNAME = "127.0.0.1";
const USERNAME = "root";
const PASSWORD = "***";
const DBNAME = "test";
const CHARSET = "utf8";
public function MysqlConnect()
{
$db = new mysqli(self::HOSTNAME, self::USERNAEM, self::PASSWORD, self::DBNAME); // 连接数据库
$db->query("set names ".self::CHARSET);
if (mysqli_connect_errno())
{
throw new MysqlException("服务器系统故障", 1001);
}
else
{
return $db;
}
}
}
?>
每次数据库连接都要new这个类, 然后调用mysqlconnect方法, 返回连接, 然后close掉连接, 频繁的new和数据库连接关闭操作非常的消耗资源!数据库软件系统中使用数据库连接池,
主要是节省打开或者关闭数据库连接所引起的效率损耗, 这种效率上的损耗还是非常昂贵的, 因为使用单例模式来维护, 就可以大大降低这种损耗。
因此, 为了避免资源消耗, 我们有了下面的改进:
<?php
class Mysql{
//该属性用来保存实例
private static $conn;
//构造函数为private,防止创建对象
private function __construct(){
$this->conn = mysql_connect('localhost','root','');
}
//创建一个用来实例化对象的方法
public static function getInstance(){
if(!(self::$conn instanceof self)){
self::$conn = new self;
}
return self::$conn;
}
//防止对象被复制
public function __clone(){
trigger_error('Clone is not allowed !');
}
}
//只能这样取得实例,不能new 和 clone
$mysql = Mysql::getInstance();
?>
这样就不用每次都来new这个类了, 方便了很多。下面给一个详细的:
<?php
class Mysql
{
private $DB;
static private $_instance;
// 连接数据库
private function __construct($host, $username, $password)
{
$this->DB = mysql_connect($host, $username, $password);
$this->query("SET NAMES 'utf8'", $this->link);
return $this->DB;
}
private function __clone(){}
public static function getInstance($host, $username, $password)
{
if( !(self::$_instance instanceof self) )
{
self::$_instance = new self($host, $username, $password);
}
return self::$_instance;
}
// 连接数据表
public function select_db($database)
{
$this->result = mysql_select_db($database);
return $this->result;
}
// 执行SQL语句
public function query($query)
{
return $this->result = mysql_query($query, $this->link);
}
// 将结果集保存为数组
public function fetch_array($fetch_array)
{
return $this->result = mysql_fetch_array($fetch_array, MYSQL_ASSOC);
}
// 获得记录数目
public function num_rows($query)
{
return $this->result = mysql_num_rows($query);
}
// 关闭数据库连接
public function close()
{
return $this->result = mysql_close($this->link);
}
}
?>
使用的时候:
$con = Mysql::getInstance($host, $username, $password);
$con -> select_db($database);
当然, 单例模式不仅仅只是应用在数据库的操作类上面。还可以应用在这些方面:
1. 网站的计数器, 一般也是采用单例模式实现, 否则难以同步。
2. 应用程序的日志应用, 一般都何用单例模式实现, 这一般是由于共享的日志文件一直处于打开状态, 因为只能有一个实例去操作, 否则内容不好追加。
3. Web应用的配置对象的读取, 一般也应用单例模式, 这个是由于配置文件是共享的资源。
PHP单例模式的缺点
众所周知, PHP语言是一种解释型的脚本语言, 这种运行机制使得每个PHP页面被解释执行后, 所有的相关资源都会被回收。也就是说, PHP在语言级别上没有办法让某个对象常驻内存,
这和asp.net、Java等编译型是不同的, 比如在Java中单例会一直存在于整个应用程序的生命周期里, 变量是跨页面级的, 真正可以做到这个实例在应用程序生命周期中的唯一性。
然而在PHP中, 所有的变量无论是全局变量还是类的静态成员, 都是页面级的, 每次页面被执行时, 都会重新建立新的对象, 都会在页面执行完毕后被清空, 这样似乎PHP单例模式就没有什么意义了,
所以PHP单例模式我觉得只是针对单次页面级请求时出现多个应用场景并需要共享同一对象资源时是非常有意义的。
相关推荐
- 运维从头到尾安装日志服务器,看这一篇就够了
-
一、rsyslog部署1.1)rsyslog介绍Linux的日志记录了用户在系统上一切操作,看日志去分析系统的状态是运维人员必须掌握的基本功。rsyslog日志服务器的优势:1、日志统一,集中式管理...
- 被MySQL慢日志查询搞废了?3分钟教你快速定位慢查询问题
-
一条慢查询会造成什么后果?刚开始使用MySQL的开发、初级DBA以为就是简单的查询变慢些,体验稍微有一丢丢影响,殊不知,慢查询的破坏力远不止如此。业务高峰期,这头SQL还没处理完,大量新的查询请求堆...
- Linux 查看系统日志 执行日志 安全日志 history 登录日志
-
修改history记录打开配置文件vim/etc/profile或~/.bash_profile显示执行的用户及其IP添加,将下面内容添加到末尾USER_IP=`who-uami2>/...
- Linux系统日志的简单分析(linux系统日志文件有哪些)
-
为了保证Linux系统正常运行、准确解决遇到的各种各样的系统问题,认真地读取日志文件是系统管理员的一项非常重要的任务。因为日志文件能够详细记录系统每天发生的各种各样的事件。用户可以通过日志文件检查错误...
- 如何按天切割日志文件(日志切割命令)
-
简单明了,直接开始,给热爱编程的你我apache修改httpd.conf对以下两行进行调整ErrorLog"|/usr/local/apache/bin/rotatelogs/data/...
- Apache 记录请求响应时间日志(apache日志查看)
-
本文章向大家介绍Apache记录请求响应时间日志,主要包括Apache记录请求响应时间日志使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。官网介绍在A...
- Linux系统LOG日志分析与管理(四)——配置Loganalyzer
-
摘要:Loganalyzer是一款syslog日志和其他网络事件数据的Web前端工具。它提供了对日志的浏览、搜索、基本分析和一些图表报告的功能。其分析所需数据可以从数据库或一般的syslog文本文件中...
- PHP-FPM 学习记录(php.fpm)
-
什么是FastCGI请阅读FastCGI(FastCommonGatewayInterface)的理解这里不再赘述什么是(PHP-FPM)PHP5.4之前只是用来管理php-cgi进程的进程管理...
- Nginx access_log 运行日志查询和配置
-
1.介绍当我们学会Nginx的基本配置之后,可以通过Nginx配置Service代理。管理服务器所有的http和https请求。那么接下来就需要了解Nginx的日志控制,以及相关的文档查看了。你通过...
- PHP 单例模式(php单例模式和工厂模式)
-
单例模式(SingletonPattern)单例模式(SingletonPattern):顾名思义,就是只有一个实例。作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向...
- PHP之单例模式(php 单例模式优点及如何实现)
-
单例模式属于创建型模式,何为创建型模式,即创建型模式抽象了实例化过程。他们帮助一个系统独立于如何创建、组合和表示他的那些对象。一个类创建型模式使用继承改变被实例化的类。而一个对象创建型模式将实例化委托...
- 2022年SEO还需要交换友情链接吗(seo还有用吗)
-
友情链接是什么意思?这是一个古老的话题,但对于现在的正规网站依然行之有效,本篇详细讲讲2022年对友情链接的理解与操作。今天,小小课堂网(www.xxkt.org.cn)带来的是《2022年SEO...
- 基于maxkb实现对话一键生成docx分析报告,支持图片和表格
-
通过扩展maxkb的知识库管理和ai对话能力,实现一键生成分析报告及word文档;本次优化点在于:实现用户输入多个问题,一键生成分析报告,并提供word文件将内容下载下来word中支持markdown...
- 新版证书查询系统源码 支持自适应多端
-
TP开发证书查询系统适用于各行业相关证书查询,基于ThinkPHP开发,可以同时多字段区配查询,后台管理界面清新,可批量导入导出数据,格式为:JSON、CSV、Excel等,自适应手机端,PC端...
- Rocky Linux 9 源码包安装php8(rocksdb 源码)
-
RockyLinux9源码包安装php8大家好,我是星哥!今天咱们不聊yum一键安装的“快餐式”部署,来点儿硬核的——源码编译安装PHP8.3。为什么要折腾源码?因为它能让你深度定制PHP功能...
- 一周热门
- 最近发表
- 标签列表
-
- 外键约束 oracle (36)
- oracle的row number (32)
- 唯一索引 oracle (34)
- oracle in 表变量 (28)
- oracle导出dmp导出 (28)
- oracle两个表 (20)
- oracle 数据库 字符集 (20)
- oracle安装补丁 (19)
- matlab化简多项式 (20)
- 多线程的创建方式 (29)
- 多线程 python (30)
- java多线程并发处理 (32)
- 宏程序代码一览表 (35)
- c++需要学多久 (25)
- css class选择器用法 (25)
- css样式引入 (30)
- css教程文字移动 (33)
- php简单源码 (36)
- php个人中心源码 (25)
- php小说爬取源码 (23)
- 云电脑app源码 (22)
- html画折线图 (24)
- docker好玩的应用 (28)
- linux有没有pe工具 (34)
- mysql数据库源码 (21)