PHP 单例模式
bigegpt 2025-04-26 16:59 5 浏览
单例模式(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单例模式我觉得只是针对单次页面级请求时出现多个应用场景并需要共享同一对象资源时是非常有意义的。
- 上一篇:Zabbix经验分享-缺包常见问题处理
- 下一篇:基于NanoMQ搭建MQTT服务器
相关推荐
- 得物可观测平台架构升级:基于GreptimeDB的全新监控体系实践
-
一、摘要在前端可观测分析场景中,需要实时观测并处理多地、多环境的运行情况,以保障Web应用和移动端的可用性与性能。传统方案往往依赖代理Agent→消息队列→流计算引擎→OLAP存储...
- warm-flow新春版:网关直连和流程图重构
-
本期主要解决了网关直连和流程图重构,可以自此之后可支持各种复杂的网关混合、多网关直连使用。-新增Ruoyi-Vue-Plus优秀开源集成案例更新日志[feat]导入、导出和保存等新增json格式支持...
- 扣子空间体验报告
-
在数字化时代,智能工具的应用正不断拓展到我们工作和生活的各个角落。从任务规划到项目执行,再到任务管理,作者深入探讨了这款工具在不同场景下的表现和潜力。通过具体的应用实例,文章展示了扣子空间如何帮助用户...
- spider-flow:开源的可视化方式定义爬虫方案
-
spider-flow简介spider-flow是一个爬虫平台,以可视化推拽方式定义爬取流程,无需代码即可实现一个爬虫服务。spider-flow特性支持css选择器、正则提取支持JSON/XML格式...
- solon-flow 你好世界!
-
solon-flow是一个基础级的流处理引擎(可用于业务规则、决策处理、计算编排、流程审批等......)。提供有“开放式”驱动定制支持,像jdbc有mysql或pgsql等驱动,可...
- 新一代开源爬虫平台:SpiderFlow
-
SpiderFlow:新一代爬虫平台,以图形化方式定义爬虫流程,不写代码即可完成爬虫。-精选真开源,释放新价值。概览Spider-Flow是一个开源的、面向所有用户的Web端爬虫构建平台,它使用Ja...
- 通过 SQL 训练机器学习模型的引擎
-
关注薪资待遇的同学应该知道,机器学习相关的岗位工资普遍偏高啊。同时随着各种通用机器学习框架的出现,机器学习的门槛也在逐渐降低,训练一个简单的机器学习模型变得不那么难。但是不得不承认对于一些数据相关的工...
- 鼠须管输入法rime for Mac
-
鼠须管输入法forMac是一款十分新颖的跨平台输入法软件,全名是中州韵输入法引擎,鼠须管输入法mac版不仅仅是一个输入法,而是一个输入法算法框架。Rime的基础架构十分精良,一套算法支持了拼音、...
- Go语言 1.20 版本正式发布:新版详细介绍
-
Go1.20简介最新的Go版本1.20在Go1.19发布六个月后发布。它的大部分更改都在工具链、运行时和库的实现中。一如既往,该版本保持了Go1的兼容性承诺。我们期望几乎所...
- iOS 10平台SpriteKit新特性之Tile Maps(上)
-
简介苹果公司在WWDC2016大会上向人们展示了一大批新的好东西。其中之一就是SpriteKitTileEditor。这款工具易于上手,而且看起来速度特别快。在本教程中,你将了解关于TileE...
- 程序员简历例句—范例Java、Python、C++模板
-
个人简介通用简介:有良好的代码风格,通过添加注释提高代码可读性,注重代码质量,研读过XXX,XXX等多个开源项目源码从而学习增强代码的健壮性与扩展性。具备良好的代码编程习惯及文档编写能力,参与多个高...
- Telerik UI for iOS Q3 2015正式发布
-
近日,TelerikUIforiOS正式发布了Q32015。新版本新增对XCode7、Swift2.0和iOS9的支持,同时还新增了对数轴、不连续的日期时间轴等;改进TKDataPoin...
- ios使用ijkplayer+nginx进行视频直播
-
上两节,我们讲到使用nginx和ngixn的rtmp模块搭建直播的服务器,接着我们讲解了在Android使用ijkplayer来作为我们的视频直播播放器,整个过程中,需要注意的就是ijlplayer编...
- IOS技术分享|iOS快速生成开发文档(一)
-
前言对于开发人员而言,文档的作用不言而喻。文档不仅可以提高软件开发效率,还能便于以后的软件开发、使用和维护。本文主要讲述Objective-C快速生成开发文档工具appledoc。简介apple...
- macOS下配置VS Code C++开发环境
-
本文介绍在苹果macOS操作系统下,配置VisualStudioCode的C/C++开发环境的过程,本环境使用Clang/LLVM编译器和调试器。一、前置条件本文默认前置条件是,您的开发设备已...
- 一周热门
- 最近发表
- 标签列表
-
- mybatiscollection (79)
- mqtt服务器 (88)
- keyerror (78)
- c#map (65)
- resize函数 (64)
- xftp6 (83)
- bt搜索 (75)
- c#var (76)
- mybatis大于等于 (64)
- xcode-select (66)
- httperror403.14-forbidden (63)
- logstashinput (65)
- hadoop端口 (65)
- dockernetworkconnect (63)
- esxi7 (63)
- vue阻止冒泡 (67)
- c#for循环 (63)
- oracle时间戳转换日期 (64)
- jquery跨域 (68)
- php写入文件 (73)
- java大写转小写 (63)
- kafkatools (66)
- mysql导出数据库 (66)
- jquery鼠标移入移出 (71)
- 取小数点后两位的函数 (73)