php 单例模式应用-改进版

来源:互联网 发布:js settimeout原理 编辑:程序博客网 时间:2024/06/02 03:39

单例模式的应用

作者:Wucl

时间:2014-11-11

章节内容:基础准备、实现方式、个人心得。

1. 基础准备:

单例顾名思义单一实例,即一次程序执行过程中一个类只有一个相同特性的实例。为了实现这个目的:首先,需要一个静态的变量存放一个类的相同特性实例,以便下次需要时直接从静态变量中取出并使用。其次,需要防止类被克隆。最后,实现实例类和如何存放相同特性的实例。

2. 实现方式(完整的方式见附录):

首先,创建单例核心类:class Singleton{}

其次,声明静态变量和防克隆method

private static $instances = array();

final private function __clone() {}

然后,实现单例化method,其中我选择使用数组键值对的方式存放实例。考虑到不同参数实例类时,产生的实例对象不相同:键=类名+字符串化参数、值=实例对象。

1) 字符串化参数的method如下:

private static function arrToStr($params = array()){

$str = '';

foreach ($params as $v=>$val){

if(is_array($val) || is_object($val)){

$val = is_object($val) ? get_object_vars($val) : $val;

$str .= 'array('.self::arrToStr($val).')';

}else{

$str .= $val.'_';

}

}

return trim($str, '_');

}

使用方式:

$class_name = get_called_class();

$instances_name = $class_name;

if(!empty(func_get_args())){

$instances_name .= '_'.self::arrToStr(func_get_args());

}

2) 单例化主体类的method如下:

final public static function instance(){

$class_name = get_called_class();

$instances_name = $class_name;

if(!empty(func_get_args())){

$instances_name .= '_'.self::arrToStr(func_get_args());

}

if (!isset(self::$instances[$instances_name]) || !(self::$instances[$instances_name] instanceof $class_name))

self::$instances[$instances_name] = self::singletonInstance($class_name, func_get_args());

return self::$instances[$instances_name];

}

3) 多参数单例化类的method如下(只提供了10个参数以下的实例)

private static function singletonInstance($class_name='', $params=array())

{

$num = count($params);

switch($num) {

case 1:

$instance = new $class_name($params[0]);

break;

case 2:

$instance = new $class_name($params[0], $params[1]);

break;

case 3:

$instance = new $class_name($params[0], $params[1], $params[2]);

break;

case 4:

$instance = new $class_name($params[0], $params[1], $params[2], $params[3]);

break;

case 5:

$instance = new $class_name($params[0], $params[1], $params[2], $params[3], $params[4]);

break;

case 6:

$instance = new $class_name($params[0], $params[1], $params[2], $params[3], $params[4], $params[5]);

break;

case 7:

$instance = new $class_name($params[0], $params[1], $params[2], $params[3], $params[4], $params[5], $params[6]);

break;

case 8:

$instance = new $class_name($params[0], $params[1], $params[2], $params[3], $params[4], $params[5], $params[6], $params[7]);

break;

case 9:

$instance = new $class_name($params[0], $params[1], $params[2], $params[3], $params[4], $params[5], $params[6], $params[7], $params[8]);

break;

case 10:

$instance = new $class_name($params[0], $params[1], $params[2], $params[3], $params[4], $params[5], $params[6], $params[7], $params[8], $params[9]);

break;

default:

$instance = new $class_name();

break;

}

return $instance;

}

4) 这是一个单例方式使用的例子:

class Db extends Singleton{

public function __construct($db = array(), $db2 = array()){}

public static function getInstance($db = array(), $db2 = array()){

return self::instance($db, $db2);

}

}

3. 个人心得:

我曾经做过一个测试,结果如下:

142600
142600
142600
144712
144768
144824

3行数字为使用单例所占内存,使用3次对象时所占内存的大小一样,

3行数字为正常实例所占内存,使用3次对象时所占内存会逐次变大。

  上述结果表明使用单例模式是有必要的,当然开始的时候我并没有考虑到不同参数的情况,以至于不同参数使用单例核心类实例出来的类,都是第一次实例的类,后面才使用func_get_args()实现了不同参数实例不同的类。这就表明我们所做每一件事,都需要一步一步的实验才能把这件事做得更好。

4. 附录(以下是完整的单例核心类,希望能帮到以后的自己和看这份文档的):

<?php

/**

*@desc: 单例模式的实现类

*@author: Wucl

*@since: 2014-09-10

*/

namespace Library\Core;

class Singleton{

private static $instances = array();

/**

*私有化__clone()方法

*/

final private function __clone() {}

/**

 * 单例化类

 * @return 返回实例类

 */

final public static function instance(){

$class_name = get_called_class();

$instances_name = $class_name;

if(!empty(func_get_args())){

$instances_name .= '_'.self::arrToStr(func_get_args());

}

if (!isset(self::$instances[$instances_name]) || !(self::$instances[$instances_name] instanceof $class_name))

self::$instances[$instances_name] = self::singletonInstance($class_name, func_get_args());

return self::$instances[$instances_name];

}

/**

 * 多维数组和对象转换成字符串

 * @param unknown $params 参数数组

 * @return string

 */

private static function arrToStr($params = array()){

$str = '';

foreach ($params as $v=>$val){

if(is_array($val) || is_object($val)){

$val = is_object($val) ? get_object_vars($val) : $val;//对象先转换为数组

$str .= 'array('.self::arrToStr($val).')';

}else{

$str .= $val.'_';

}

}

return trim($str, '_');

}

/**

 * 多参数实例

 * @param unknown $class_name

 * @param unknown $params

 */

private static function singletonInstance($class_name='', $params=array()){

$num = count($params);

switch($num) {

case 1:

$instance = new $class_name($params[0]);

break;

case 2:

$instance = new $class_name($params[0], $params[1]);

break;

case 3:

$instance = new $class_name($params[0], $params[1], $params[2]);

break;

case 4:

$instance = new $class_name($params[0], $params[1], $params[2], $params[3]);

break;

case 5:

$instance = new $class_name($params[0], $params[1], $params[2], $params[3], $params[4]);

break;

case 6:

$instance = new $class_name($params[0], $params[1], $params[2], $params[3], $params[4], $params[5]);

break;

case 7:

$instance = new $class_name($params[0], $params[1], $params[2], $params[3], $params[4], $params[5], $params[6]);

break;

case 8:

$instance = new $class_name($params[0], $params[1], $params[2], $params[3], $params[4], $params[5], $params[6], $params[7]);

break;

case 9:

$instance = new $class_name($params[0], $params[1], $params[2], $params[3], $params[4], $params[5], $params[6], $params[7], $params[8]);

break;

case 10:

$instance = new $class_name($params[0], $params[1], $params[2], $params[3], $params[4], $params[5], $params[6], $params[7], $params[8], $params[9]);

break;

default:

$instance = new $class_name();

break;

}

return $instance;

}

}

?>

0 0