收藏文章 楼主
PHP4之真OO
网友【血蜘蛛】 2005-06-20 20:00:09 分享在【时代发展的印记】版块    1    1
本文的作者Johan Persson是PHP中著名的JpGraph图表类库的开发者。本文是作者对于在PHP4中进行面向对象开发时需要注意的几个小问题的总结。

翻译: Binzy Wu [Mail: Binzy at JustDN dot COM], 水平有限, 欢迎探讨。

原文Url: aditus.nu/jpgraph/jpg_phpoo.php

简介

本文的对象是那些曾使用更加成熟的OO语言, 如Eiffel, Java, C#2 or C++(), 进行开发的朋友(如我自己).。在使用PHP4进行完全的OO开发时有着许多的语义3 (semantic) 上的陷阱4.

希本文内容可助人避我曾犯之错.

引用 VS 拷贝语义

这基本上是错误的主要来源(至少对于我来说).即使在PHP的文档中你可以读到PHP4较之引用更多使用拷贝语义(如其他我所知的面向对象语言), 但这仍将使你最后在一些细小之处困扰.

接下来的两部分用于阐述二个小的例子, 在这二个例子中拷贝语义也许会令你惊讶.要时刻牢记重要的是一个类的变量不是一个指向类的指针而是实际的类自己本身5. 大多数问题引发自对于赋值操作符(=)的误解, 即以为是给一个对象一个别名, 而实际上却是一个新的拷贝. 例如假设$myObj是某个类的实例, 并且它有一个Set()方法. 那么下面的代码也许不会像一个C++(或者Java)程序员所期望的那样工作.

代码:function SomeFunction($aObj) { $aObj->Set(10); } … SomeFunction ($myObj); …

那么现在, 很容易便会认为该函数所调用的Set()方法会作用于$myObj. 但这是错的! 其实发生的是$myObj被拷贝为一个新的, 与原对象一样的拷贝----参数$aObj. 然后当Set()方法被调用时, 它仅仅作用于本地拷贝而非原参数----$myObj. 在包含直接或间接(如上)赋值操作的地方就会发生各种各样的上述问题. 为了函数能像你所期望的那样行动(也许是), 那么你不得不通过修改方法申明来告诉PHP使用引用来传递对象, 如:

代码:Function SomeFunction(&$aObj)

如果你再一次尝试上面的代码, 那么你会发现Set()方法将作用于原来的参数上, 因为现在我们在作用中创建了一个$myObj的别名----$aObj. 但是你不得不小心, 因为即使是&操作符也不是在任何时候都能救你, 如下面的举例.

从一个引用来获得引用

假设有如下代码:

代码:$myObject = new SomeClass();$myRefToObject = &$myObject;

如果我们现在想要一个引用的拷贝(因某些理由), 那么我们要做什么呢? 你可能会由于$myRefToObject已经是引用而试图那么写:

代码:$myCopyRefToObject = $myRefToObject;

正确么? 不! PHP会创建$myRefToObject所引用对象的新拷贝. 如果你想拷贝一个对象的引用, 你不得不这么写:

代码:$myCopyRefToObject = &$myRefToObject;

在与前所述例子相当的C++的例子中, 便会创建一个引用的引用. 与其在PHP中不同. 这是一个经验丰富的C++程序员常会作的直觉假设相反的, 而这会是你的PHP程序中小BUG的来源.

请小心由此所产生的间接(传递参数)或直接的问题.

我个人所达成的结论, 即最好的避免这些语义陷阱的方法是总是用引用来传递对象或者对象赋值. 这不仅仅改进了运行速度(更少的数据拷贝), 而且可以对像我这样的老狗而言使语义更加可预测.

在构造函数中对$this使用引用

在一个对象的构造函数里初始化作为其他对象发现者(Observer6)的对象是一个常见的模式. 下面几行代码便是一个示例:

代码:class Bettery { function Bettery() {…}; function AddObserver($method, &$obj) { $this->obs[] = array($obj, &$method) } function Notify(){…} } class Display { function Display(&$batt) { $batt->AddObserver("BatteryNotify",$this); } function BatteryNotify() {…} }

但是, 这并不会正常工作, 如果你是这么实例化对象的:

代码:$myBattery = new Battery();$myDisplay = new Display($myBattery);

这么做的错误在于new时在构造函数中使用$this并不会返回同一个对象. 反而会返回最近创建对象的一个拷贝. 即在调用AddObserver()时所传送的对象于原对象不是同一个.然后当Battery类尝试通知所有它的观察者(Observer)(通过调用他们的Notify方法)时, 它并不会调用我们所创建的Display类而是$this所代表的类(即我们所创建的Display类的拷贝). 因此如果Notify()方法更新了一些实例变量, 并不像我们所设想原Display类会被更新, 因为更新的其实是个拷贝.

为了让它工作, 你必须使构造函数返回同一个对象, 正如与最初$this所象征的那样. 可以通过添加&符号于Display的构造, 如$myDisplay = & new Display($myBattery);一个直接的结果是任何Display类的Client必须了解Display的实现细节. 事实上, 这会产生一个可能引起争论的问题: 所有对象的构建必须使用额外的&符号. 就我所说的基本上是安全的, 但忽略它可能会在某些时候得到不想要的如上述示例般的作用.

在JpGraph中使用了另一种方法来解决. 即需要使用通过添加一个能安全的使用&$this引用的”Init()”方法的所谓二阶段构造来”new”一个对象(仅仅是因为在构造函数中的$this引用返回对象的一个拷贝而不如所期望的那样执行). 因此上面的例子会如下实现:

代码:$myBattery = new Battery(); $myDisplay = new Display(); $myDisplay->Init($myBattery);

如JPGraph.php中的”LinearScale”类.

使用foreach

另外一个相似代码却不同结果的问题是”foreach”结构的问题. 研究一下下面的二个循环结构的不同版本.

代码:// Version 1foreach( $this->plots as $p ){ $p->Update();}…// Version 2for( $i=0; $iplots); ++$i ) {$this->plots[$i]->Update();}

现在是一个价值10美元的问题: version1==version2么?

令人惊讶的答案是:No! 这是细小却是关键的不同. 在Version 1中, Update()方法将作用于”plots[]”数组中对象的副本. 因此数组中原来的对象并不会被更新.

在Version 2中Update()方法将如预期的作用于”plots[]”数组中的对象.

正如第一部分所陈述的, 这是PHP将对象实例作为对象本身来处理而非作为对象引用的结果.

译注:

1. OO: Object-Oriented, 面向对象.

2. 原文并无C#, 全因Binzy的个人爱好.

3. Semantic在本文中被译为”语义”, 如有任何建议请和Binzy联系.

4. C++中有一本著名的”C++ Gotchas”.

5. 这里的类应该是指Instance, 即实例.

6. 可参见”[GoF95]”, 即”Design Patterns”.

7. 有个挺有趣的关于交易的小故事:

有人用60美元买了一匹马, 又以70美元的价钱卖了出去;然后, 他又用80美元把它买回来, 最后以90美元的价钱卖出.在这桩马的交易中, 他? (A)赔了10美元; (B)收支平衡; (C)赚了10美元;(D)赚了20美元; (E)赚了30美元.

这是美国密执安大学心理学家梅尔和伯克要大学生们计算的一个简单的算术题.结果只有不到40%的大学生能够作出正确答案, 多数人认为只赚了10美元.其实, 问题的条件十分明确, 这是两次交易, 每次都赚10美元, 而很多人却错误地认为当他用80美元买回来时己经亏损了10美元. 有趣的是, 同一问题, 以另一种方式提出来:有一个人用60美元买了一匹白马, 又以70元的值卖出去;然后, 用80美元买了一匹黑马, 又以90美元的值卖出去.在这桩买卖马的交易中, 他____(把同样的五个选择罗列出来).这时, 另一组大学生在回答上述问题时, 结果大家都答对了.

在PHP5中对象模型的确是更加正确和先进了。甚至是array这样的函数在传递对象参数的时候也进行引用而非拷贝.以下php5下的Observer模式示例代码可说明. 但很多的PHP程序员并没有意识到PHP4中对象的问题.

代码:/*
*
* Binzy Wu
*
* */

class Observer
{
private $objList = array();
function __construct()
{
// nothing
}

function addObserver($subject, $method)
{
$this->objList[] = array($subject, $method);
}

public function Notify()
{
for($i=0;$iobjList);$i++)
{
$obj = $this->objList[$i][0];
$method = $this->objList[$i][1];
$obj->$method();
}
}
}
class Subject
{

public $no;

function __construct($observer, $num)
{
$this->no = $num;
$observer->addObserver($this, "test");
}

public function test()
{
print $this->no;
}
}

$observer = new Observer();
$subject = new Subject($observer, 0);

$subject->no = 2;

$observer->Notify();

?>

正如Mr.Perrson说的,本文的目的是给使用java,.net的程序员在使用PHP4时的建议。

出处:CSDN
meiguo.com 发布人签名/座右铭·有时你看似是一件很吃亏的事,往往会变成非常有得的事。
·凡事都留有余地,因为人是人,不是神,不免有错处,可以原谅人的地方,就原谅人。
·好的时候不要看得太好,坏的时候不要看的太坏。
大家都在看
回复/评论列表
默认   热门   正序   倒序
meiguo.com 创始人

emotion

1   2005-06-20 20:00:09  回复

回复/评论:PHP4之真OO

暂无用户组 升级
退出
等级:0级
美果:
美过
精华推荐
  1. 这小伙年仅25岁,已经是百亿美金公司的创始CEO了!
  2. AI半壁江山是中国人?黄仁勋“敲警钟”:美国须觉醒!
  3. 华人科学家再次遭遇系统性排查,75%留美学者“萌生去意”!
  4. 关于“跨国婚姻”婚姻绿卡,给配偶申请绿卡的各种细节问题!
  5. 关税战持续了96小时… 突然大反攻?
  6. 独自搭乘美国硬座火车,52小时横穿美国!
  7. 百万民众“上街游行”抗议川普政府的百天?
  8. 童工可以合法夜班了?
  9. 马斯克的丑闻?和多名女性有染,有上百个孩子?
  10. 川普关税政策可能导致意外后果
  11. 中国的中产家庭,送孩子赴美留学就是鸡肋之举?
  12. 美国“大规模”取消国际留学生的签证
  13. 遭遇无故吊销学签,藤校的中国留学生起诉且赢了🇺🇸国土安全部!
  14. 盘点美国最繁华的城市 top10
  15. 美国小伙儿在武当山修行十余年,终于获得“中国绿卡”了!
  16. 中方意识到谈判时机已至?迅速派出“王牌代表应邀”和美国财长会面了
  17. 【读懂AI Agent】MetaGPT、Mila、斯坦福、耶鲁、谷歌的合作论文
  18. 瞄准美国公民了?川普总统的“驱逐行动”在变本加厉
  19. 中国“不陪川普玩”了… 从此不理会美方闹剧!
  20. 这位美国年轻人在中国玩儿一圈,浪费掉美国政府的16亿美金?
  21. 台湾政府:一场误会呀
  22. 美国华人在近期出入境美国,绿卡和签证的持有者须知!
  23. 近半数中国小包裹的接收人是贫困美国百姓?
  24. 美国《时代》周刊:DeepSeek【梁文锋】
  25. “240小时免签”和“离境退税”叠加组合,让美国人感受到了中国人的聪明智慧!
  26. 美国驻华大使馆:“赴美生子”一律拒签
  27. 中美博弈2.0了?川普政府“百日执政”,撤回对华善意!
  28. 川普总统:在未来几周内开始发放“金卡签证”
  29. 哪些关键技术决定了如今大模型格局?Google的首席科学家“万字演讲”回顾AI发展的十年
  30. 美国人在凌晨三点排队,不为苹果手机… 竟然是为中国毛绒玩具“拉布布”?
  31. BBC:在川普政府的关税打击下,为何中国不低头?
  32. 中美关税战的最佳写实作品~乌合麒麟发布《就不跪》
  33. 贸易战的结局已定?中美两国“各退一步”?
  34. 在量子世界“玩儿游戏”?物理学家展示了量子计算机的新前景
  35. 2025年,必须认识的一个英文单词 ~ tariff
  36. 让人意外!股神【巴菲特】突然宣布退休

美国动态 美果搜索

Your IP: 18.218.106.172, 2025-05-16 22:38:38

Processed in 0.07626 second(s)

头像

用户名:

粉丝数:

签名:

资料 关注 好友 消息
已有0次打赏
(1) 分享
分享
取消