PHP实现单例模式
<p>单例模式的定义:保证一个类<strong>只有一个</strong>实例,并提供一个访问它的全局访问点。</p><p>PHP实现单例模式:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Singleton
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建静态私有的变量保存该类对象</span>
<span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(128, 0, 128, 1)">$instance</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">防止使用new直接创建对象</span>
<span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> __construct(){}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">防止使用clone克隆对象</span>
<span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> __clone(){}
</span><span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getInstance()
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">判断$instance是否是Singleton的对象,不是则创建</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (!self::<span style="color: rgba(128, 0, 128, 1)">$instance</span><span style="color: rgba(0, 0, 0, 1)"> instanceof self) {
self</span>::<span style="color: rgba(128, 0, 128, 1)">$instance</span> = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> self();
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span> self::<span style="color: rgba(128, 0, 128, 1)">$instance</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> test()
{
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> "我是一个单例模式"<span style="color: rgba(0, 0, 0, 1)">;
}
}
</span><span style="color: rgba(128, 0, 128, 1)">$sing</span> = Singleton::<span style="color: rgba(0, 0, 0, 1)">getInstance();
</span><span style="color: rgba(128, 0, 128, 1)">$sing</span>-><span style="color: rgba(0, 0, 0, 1)">test();
</span><span style="color: rgba(128, 0, 128, 1)">$sing2</span> = <span style="color: rgba(0, 0, 255, 1)">new</span> Singleton(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">Fatal error: Uncaught Error: Call to private Singleton::__construct() from invalid context in</span>
<span style="color: rgba(128, 0, 128, 1)">$sing3</span> = <span style="color: rgba(0, 0, 255, 1)">clone</span> <span style="color: rgba(128, 0, 128, 1)">$sing</span>; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">Fatal error: Uncaught Error: Call to private Singleton::__clone() from context</span></pre>
</div>
<p> </p>
<p>PHP实现单例模式有什么意义:</p>
<p><span style="font-size: 13px">没有意义,PHP没有线程概念,没有异步代码,不会常驻内存,所有的修改自己都可以控制,不需要保证类只有一个实例,有什么意义?你要在数据库连接类中使用单例模式,万一有的页面需要连接两个数据库怎么办?</span></p>
<p><span style="font-size: 13px">真的没有意义吗?</span></p>
<p><span style="font-size: 13px">当然不是。</span></p>
<p><span style="font-size: 13px">看下代码:</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> A
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> show()
{
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> "我是A类函数,要调用B类函数和C类函数<br/>"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(128, 0, 128, 1)">$b</span> = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> B();
</span><span style="color: rgba(128, 0, 128, 1)">$b</span>-><span style="color: rgba(0, 0, 0, 1)">show();
</span><span style="color: rgba(128, 0, 128, 1)">$c</span> = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> C();
</span><span style="color: rgba(128, 0, 128, 1)">$c</span>->show('A'<span style="color: rgba(0, 0, 0, 1)">);
}
}
</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> B
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> show()
{
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> "我是B类函数,要调用C类函数<br/>"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(128, 0, 128, 1)">$c</span> = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> C();
</span><span style="color: rgba(128, 0, 128, 1)">$c</span>->show('B'<span style="color: rgba(0, 0, 0, 1)">);
}
}
</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> C
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">function</span> show(<span style="color: rgba(128, 0, 128, 1)">$parm</span><span style="color: rgba(0, 0, 0, 1)">)
{
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> "我是C类函数,现在被{<span style="color: rgba(128, 0, 128, 1)">$parm</span>}类函数调用<br/>"<span style="color: rgba(0, 0, 0, 1)">;
}
}
</span><span style="color: rgba(128, 0, 128, 1)">$a</span> = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> A();
</span><span style="color: rgba(128, 0, 128, 1)">$a</span>->show();</pre>
</div>
<p> <span style="font-size: 15px">这里调用的过程中,创建了两个C类对象,我们知道,new是很耗资源的一种操作,如果这里C类是单例模式,只new一次就行了,这个想法是可以的,但我们一般用另外一种方法来做:</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> A
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> show()
{
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> "我是A类函数,要调用B类函数和C类函数<br/>"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(128, 0, 128, 1)">$b</span> = Unit::getInstance('B'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(128, 0, 128, 1)">$b</span>-><span style="color: rgba(0, 0, 0, 1)">show();
</span><span style="color: rgba(128, 0, 128, 1)">$c</span> = Unit::getInstance('C'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(128, 0, 128, 1)">$c</span>->show('A'<span style="color: rgba(0, 0, 0, 1)">);
}
}
</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> B
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> show()
{
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> "我是B类函数,要调用C类函数<br/>"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(128, 0, 128, 1)">$c</span> = Unit::getInstance('C'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(128, 0, 128, 1)">$c</span>->show('B'<span style="color: rgba(0, 0, 0, 1)">);
}
}
</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> C
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> __construct()
{
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> "C类对象被创建<br/>"<span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">function</span> show(<span style="color: rgba(128, 0, 128, 1)">$parm</span><span style="color: rgba(0, 0, 0, 1)">)
{
</span><span style="color: rgba(0, 0, 255, 1)">echo</span> "我是C类函数,现在被{<span style="color: rgba(128, 0, 128, 1)">$parm</span>}类函数调用<br/>"<span style="color: rgba(0, 0, 0, 1)">;
}
}
</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Unit
{
</span><span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">function</span> getInstance(<span style="color: rgba(128, 0, 128, 1)">$class</span><span style="color: rgba(0, 0, 0, 1)">)
{
</span><span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(128, 0, 128, 1)">$arr</span> = <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 255, 1)">isset</span>(<span style="color: rgba(128, 0, 128, 1)">$arr</span>[<span style="color: rgba(128, 0, 128, 1)">$class</span>]) || !<span style="color: rgba(128, 0, 128, 1)">$arr</span>[<span style="color: rgba(128, 0, 128, 1)">$class</span>] instanceof <span style="color: rgba(128, 0, 128, 1)">$class</span><span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(128, 0, 128, 1)">$arr</span>[<span style="color: rgba(128, 0, 128, 1)">$class</span>] = <span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(128, 0, 128, 1)">$class</span><span style="color: rgba(0, 0, 0, 1)">();
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 128, 1)">$arr</span>[<span style="color: rgba(128, 0, 128, 1)">$class</span><span style="color: rgba(0, 0, 0, 1)">];
}
}
</span><span style="color: rgba(128, 0, 128, 1)">$a</span> = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> A();
</span><span style="color: rgba(128, 0, 128, 1)">$a</span>->show();</pre>
</div>
<p><span style="font-size: 15px">执行代码可以看到,C类只被实例化了一次,再实际操作中,我们一般使用静态变量保存对象,变相实现单例模式。</span></p>
<p><strong><span style="font-size: 15px">单例模式和使用静态变量实现单例的区别:</span></strong></p>
<p><span style="font-size: 15px">单例模式强制类只能创建一个对象,一般是安全或者统一界面展示的时候会用到,而静态变量实现单例主要是为了减少new操作,并不能阻止new和clone操作。</span></p>
<p> </p><br><br>
来源:https://www.cnblogs.com/shamohai/p/11158206.html
頁:
[1]