[讨论]:PHP中最迷糊人的地方:静态变量与引用(喜欢开发框架的进)

fxs_2008 2011-01-03 09:40:22
许多人都认为自已的PHP很不错,连我一样.但实际上可能仍是浮在上面.






class CI_Base {

public $start = 1;


private static $instance;

public function CI_Base()
{
self::$instance =& $this;
}

public static function &get_instance()
{
return self::$instance;
}
}

function &get_instance()
{
return CI_Base::get_instance();
}



$N = new CI_Base();




$A = &get_instance();

var_dump($A);




这个一段ci框架的核心基本类的代码.知识函盖类,类实例引用,静态变量,方法,引用,垃圾收集,很有意思 如果能理解透.说明PHP已基本上过关了.



...全文
1523 40 打赏 收藏 转发到动态 举报
写回复
用AI写文章
40 条回复
切换为时间正序
请发表友善的回复…
发表回复
hipop 2011-08-27
  • 打赏
  • 举报
回复
这个写法返回最后一个实例,并不是严格的单例模式。
xiachao2008 2011-01-10
  • 打赏
  • 举报
回复
高手如云啊 收教了
helloyou0 2011-01-04
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 fxs_2008 的回复:]

再看静态变量

手册, global和静态变量都是引用.

PHP code



function test(){
global $a; //实质是 $a = & $GLOBAL['a'];



}

变量范围的另一个重要特性是静态变量(static variable)。静态变量仅在局部函数域中存在,但当程序执行离开此作用域时,其值并不丢失。看看下面的例子:

[c……
[/Quote]


函数里的static在C中也存在,和Global不同,
在外部不可见,但是再次调用函数时,值不重置.

function mycount(){
static $i;
$i=$i+1;
return $i;
}


echo mycount();
echo mycount();
echo mycount();
echo mycount();

// 1234


xuzuning 2011-01-04
  • 打赏
  • 举报
回复
不知是你想得太复杂,还是我想的太简单了
CI最初是用php4写成的,进入php5以后并没有做重大调整。只是简单的引入了php5的部分元素

private static $instance;
这在php4中是不存在的
在php4中应写放在 get_instance 方法中

之所以还要 new CI_Base();
是因为在沿袭php4时,只能这样实例化对象




fxs_2008 2011-01-04
  • 打赏
  • 举报
回复
[Quote=引用 32 楼 xeqtrl982 的回复:]

To:fxs_2008
小弟实在搞不懂单例在PHP中的应用场合。请指点
传送
[/Quote]

偶也不知道,没研究过设计模式,但看代码,单例应是只能实例化一次。它保证了对象的唯一性。而不是多态
第二个,可以保证一直引用这个对象。

引用在框架中普遍存在,应是为提高效率。

xeqtrl982 2011-01-04
  • 打赏
  • 举报
回复
To:fxs_2008
小弟实在搞不懂单例在PHP中的应用场合。请指点
传送
fxs_2008 2011-01-04
  • 打赏
  • 举报
回复
[Quote=引用 25 楼 helloyou0 的回复:]

另外,这个单例模式显然不够完美(部分原因是为了兼容旧代码)

17楼的是相对流行(规范)的写法.
使用时不需要new(也不应该new)
当然只能在php5里运行.

所以,看代码最好还是看Zend framework的,更标准
[/Quote]

是的,看上去不像是单例,因为它是可以new的,因为cotroller类会扩展它,而且可以实例化。不知CI这样的用意何在?我测试过,如果实例化多次,$A = &get_instance();仅返回最后一个。不实例化时,返回null.

17楼的代码不用实例,即可返回对象。

顺便贴了下手册的单例:


单例模式

class Example
{
// 保存类实例在此属性中
private static $instance;

// 构造方法声明为private,防止直接创建对象
private function __construct()
{
echo 'I am constructed';
}

// singleton 方法
public static function singleton()
{
if (!isset(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c;
}

return self::$instance;
}

// Example类中的普通方法
public function bark()
{
echo 'Woof!';
}

// 阻止用户复制对象实例
public function __clone()
{
trigger_error('Clone is not allowed.', E_USER_ERROR);
}

}



这样我们可以得到一个独一无二的Example类的对象。


// 这个写法会出错,因为构造方法被声明为private
$test = new Example;

// 下面将得到Example类的单例对象
$test = Example::singleton();
$test->bark();

// 复制对象将导致一个E_USER_ERROR.
$test_clone = clone $test;







在-云端 2011-01-04
  • 打赏
  • 举报
回复
个人判断应该可以这样理解!

在单个进程里,声明某个静态变量之后,之后所有的不论是再声明或者引用都是调用同一块内存数据!
在-云端 2011-01-04
  • 打赏
  • 举报
回复
[Quote=引用 27 楼 fxs_2008 的回复:]

PHP code


function mycount(){
static $i;
$i=$i+1;
return $i;
}


echo mycount();
echo mycount();
echo mycount();
echo mycount();



测了一下,确实如此,函数外变量不可见,但不知CI的函数内部声明这个变量不何意义,如12楼,能节省变量申请空间?另外……
[/Quote]


class ck{
public static function mycount(){
static $i;
$i=$i+1;
return $i;
}
}



echo ck::mycount();
echo ck::mycount();
echo ck::mycount();
echo ck::mycount();

//结果还是1234
在-云端 2011-01-04
  • 打赏
  • 举报
回复
[Quote=引用 24 楼 helloyou0 的回复:]

引用 19 楼 fxs_2008 的回复:

再看静态变量

手册, global和静态变量都是引用.

PHP code



function test(){
global $a; //实质是 $a = & $GLOBAL['a'];



}

变量范围的另一个重要特性是静态变量(static variable)。静态变量仅在局部函数域……
[/Quote]

这个静态变量是如何存储的!
fxs_2008 2011-01-04
  • 打赏
  • 举报
回复


function mycount(){
static $i;
$i=$i+1;
return $i;
}


echo mycount();
echo mycount();
echo mycount();
echo mycount();


测了一下,确实如此,函数外变量不可见,但不知CI的函数内部声明这个变量不何意义,如12楼,能节省变量申请空间?另外不知static能否在类函数内声明?
deyygywxf 2011-01-04
  • 打赏
  • 举报
回复
都是高手
zhuangsirui 2011-01-04
  • 打赏
  • 举报
回复
汗颜,都是高手。自学一年多的php了,感觉现在处在一个瓶颈,不知道怎么突破……
xuzuning 2011-01-04
  • 打赏
  • 举报
回复
没有本质的区别!

17楼的:
self::$instance = new CI_Base();
由于构造函数是私有的(private)
所以你无法在外部显式的 new

与顶层的:
self::$instance =& $this;
当你创建一个实例时保存该实例的引用

我以为,这两种方式都不能保证所谓的“单例”
他们都只是“初始化”实例
fxs_2008 2011-01-04
  • 打赏
  • 举报
回复
[Quote=引用 34 楼 xuzuning 的回复:]

不知是你想得太复杂,还是我想的太简单了
CI最初是用php4写成的,进入php5以后并没有做重大调整。只是简单的引入了php5的部分元素

private static $instance;
这在php4中是不存在的
在php4中应写放在 get_instance 方法中

之所以还要 new CI_Base();
是因为在沿袭php4时,只能这样实例化对象





……
[/Quote]
实例化可能是为兼容代码。但

17楼的:
self::$instance = new CI_Base();
与顶层的:
self::$instance =& $this;
有何区别:



helloyou0 2011-01-04
  • 打赏
  • 举报
回复
另外,这个单例模式显然不够完美(部分原因是为了兼容旧代码)

17楼的是相对流行(规范)的写法.
使用时不需要new(也不应该new)
当然只能在php5里运行.

所以,看代码最好还是看Zend framework的,更标准
fxs_2008 2011-01-03
  • 打赏
  • 举报
回复

再看看下面这个static


function log_message($level = 'error', $message, $php_error = FALSE)
{
static $LOG; //看看这个,声明这个静态变量有何用?

$config =& get_config();
if ($config['log_threshold'] == 0)
{
return;
}

$LOG =& load_class('Log');
$LOG->write_log($level, $message, $php_error);
}
fxs_2008 2011-01-03
  • 打赏
  • 举报
回复
手册对静态变量和引用说的并不详细.
问题一:静态变量是什么? 没说,只所在函数作用域存在
问题二: 对象引用,说的不明白
问题三:引用自身的问题?可能存在死环



public function CI_Base()
{
self::$instance =& $this; //这个也很奇怪,引用了自身,而只有实例中才有$this,且不报错,难以理解
}


战斗生活 2011-01-03
  • 打赏
  • 举报
回复
有点意思而已
ihefe 2011-01-03
  • 打赏
  • 举报
回复

echo "<pre/>";
$N = new CI_Base();

unset($N);//摧毁

$A = &get_instance();//这就是函盖类吧?

echo $A->start;

echo "\n";

var_dump($A);

加载更多回复(18)

4,251

社区成员

发帖
与我相关
我的任务
社区描述
国内外优秀PHP框架讨论学习
社区管理员
  • Framework
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧