第十五节--Zend引擎的发展


Posted in PHP onNovember 16, 2006

/*
+-------------------------------------------------------------------------------+
| = 本文为Haohappy读<<Core PHP Programming>> 
| = 中Classes and Objects一章的笔记 
| = 翻译为主+个人心得 
| = 为避免可能发生的不必要的麻烦请勿转载,谢谢 
| = 欢迎批评指正,希望和所有PHP爱好者共同进步! 
| = PHP5研究中心: http://blog.csdn.net/haohappy2004
+-------------------------------------------------------------------------------+
*/
第十五节--Zend引擎的发展
本章的最后一节,Zeev讨论了Zend引擎带来的对象模型,特别提到它与PHP的前几个版本中的模型有什么不同.
当1997年夏天,我们开发出PHP3, 我们没有计划要使PHP具备面向对象的能力. 当时没有任何与类和对象有关的想法. PHP3是一个纯粹面向过程的语言. 但是,在1997.8.27的晚上PHP3 alpha版中增加了对类的支持. 增加一个新特性给PHP,当时仅需要极少的讨论,因为当时探索PHP的人太少. 于是从1997年八月起, PHP迈出了走向面向对象编程语言的第一步.
确实,这只是第一步. 因为在这个设计中只有极少的相关的想法,对于对象的支持不够强大. 这个版本中使用对象仅是访问数组的一个很酷的方法而已. 取代使用$foo[“bar”],你可以使用看起来更漂亮的$foo->bar. 面向对象方法的主要的优势是通过成员函数或方法来储存功能. 例子6.18中显示了一个典型的代码块. 但是它和例6.19中的做法其实并没有太大不同.
Listing 6.18 PHP 3 object-oriented programming PHP3中的面向对象编程

<?php   
   class Example   
   {   
       var $value = "some value";   
       function PrintValue()   
       {   
           print $this->value;   
       }   
   }   
   $obj = new Example();   
   $obj->PrintValue();   
?>  
Listing 6.19 PHP 3 structural programming PHP3 PHP3中的结构化编程
<?php   
   function PrintValue($arr)   
   {   
       print $arr["value"];   
   }   
   function CreateExample()   
   {   
       $arr["value"] = "some value";   
       $arr["PrintValue"] = "PrintValue";   
       return $arr;   
   }   
   $arr = CreateExample();   
   //Use PHP's indirect reference   
   $arr["PrintValue"]($arr);   
?>  
以上我们在类中写上两行代码,或者显示地传递数组给函数. 但考虑到PHP3中这两种选择并没有任何不同,我们仍然可以仅把对象模型当成一种”语法上的粉饰”来访问数组. 
想要用PHP来进行面向对象开发的人们,特别是想使用设计模式的人,很快就发现他们碰壁了. 幸运地,当时(PHP3时代)没有太多人想用PHP来进行面向对象开发.
PHP4改变了这种情况. 新的版本带来了引用(reference)的概念, 它允许PHP的不同标识符指向内存中的同一个地址. 这意味着你可以使用两个或更多的名称来给同一个变量命名,就像例6.20那样.
Listing 6.20 PHP 4 references PHP4中的引用
<?php   
   $a = 5;   
   //$b points to the same place in memory as $a $b与$a指向内存中同个地址   
   $b = &$a;   
   //we're changing $b, since $a is pointing to 改变$b,指向的地址改变   
   //the same place - it changes too $a指向的地址也改变   
   $b = 7;   
   //prints 7  输出7   
   print $a;   
?>  
由于构建一个指向彼此的对象网络是所有面向对象设计模式的基础,这个改进具有非常重大的意义.当引用允许建立更多强大的面向对象应用程序, PHP对待对象和其它类型数据相同的做法带给开发者极大的痛苦.就像任何PHP4的程序员将会告诉你的, 应用程序将会遭遇WTMA(Way Too Many Ampersands过多&)综合症. 如果你想构建一个实际应用,你会感到极为痛苦,看看例6.21你就明白.
Listing 6.21 Problems with objects in PHP 4 PHP4中使用对象的问题
1    class MyFoo {   
2        function MyFoo()   
3        {   
4            $this->me = &$this;   
5            $this->value = 5;   
6        }   
7   
8        function setValue($val)   
9        {   
10            $this->value = $val;   
11        }   
12   
13        function getValue()   
14        {   
15            return $this->value;   
16        }   
17   
18        function getValueFromMe()   
19        {   
20            return $this->me->value;   
21        }   
22    }   
23   
24        function CreateObject($class_type)   
25        {   
26            switch ($class_type) {   
27                case "foo":   
28                    $obj = new MyFoo();   
29                    break;   
30                case "bar":   
31                    $obj = new MyBar();   
32                    break;   
33            }   
34            return $obj;   
35        }   
36   
37        $global_obj = CreateObject ("foo");   
38        $global_obj->setValue(7);   
39   
40        print "Value is " . $global_obj->getValue() . "\n";   
41        print "Value is " . $global_obj->getValueFromMe() . "\n";  

让我们一步步来讨论. 首先,有一个MyFoo类.在构造函数里,我们给$this->me一个引用,并设定
我们有其它三个成员函数: 一个设定this->value的值;一个返回this->value的值;另一个返回this->value->me的值. 但是--$this不是相同的东西吗? MyFoo::getValue()和MyFoo::getValueFromMe()返回的值不是一样的吗?
首先,我们调用CreateObject("foo"),这会返回一个MyFoo类型的对象. 然后我们调用MyFoo::setValue(7). 最后,我们调用MyFoo::getValue() 和MyFoo::getValueFromMe(), 期望得到返回值7.
当然,如果我们在任何情况下都得到7, 以上这个例子将不是本书中最没有意义的例子. 所以我相信你已经猜到—我们得不到两个7这样的结果.
但是我们将得到什么结果,并且更重要地,为什么呢?
我们将得到的结果分别是7和5. 至于为什么—--有三个很好的理由.
首先,看构造函数. 当在构造函数内部,我们在this和this->me间建立引用. 换句话说,this和this->me是同个东西. 但是我们是在构造函数内. 当构造函数结束,PHP要重新建立对象(new MyFoo的结果,第28行)分配给$obj. 因为对象没有特殊化对待,就像其它任何数据类型一样,赋值X给Y意味着Y是X的一个副本. 也就是说,obj将是new MyFoo的一个副本,而new MyFoo是一个存在于构造函数的对象. Obj->me怎么样呢? 因为它是一个引用,它原封不动仍然指向原来的对象—this. Voila-obj和obj->me不再是同个东西了—改变其中一个另一个不变.
以上是第一条理由. 还有其它类似于第一条的理由. 奇迹般地我们打算克服实例化对象这个问题(第28行). 一旦我们把CreateObject返回的值赋给global_object,我们仍然要撞上相同的问题—global_object将变成返回值的一个副本,并且再次地,global_object和global_object->me将不再相同. 这就是第二条理由.
但是,事实上我们还走不了那么远— 一旦CreateObject返回$obj,我们将破坏引用(第34行) . 这就是第三条理由.
那么,我们如何改正这些? 有两个选择. 一是在所有地方增加&符号,就像例6.22那样(第24, 28, 31, 37行). 二.如果你幸运地使用上了PHP5,你可以忘了以上这一切,PHP5会自动为你考虑这些. 如果你想知道PHP5是如何考虑这些问题的,继续阅读下去.
Listing 6.22 WTMA syndrome in PHP 4 PHP4中的WTMA综合症
1    class MyFoo {   
2        function MyFoo()   
3        {   
4            $this->me = &$this;   
5            $this->value = 2;   
6        }   
7   
8        function setValue($val)   
9        {   
10            $this->value = $val;   
11        }   
12   
13        function getValue()   
14        {   
15            return $this->value;   
16        }   
17   
18        function getValueFromMe()   
19        {   
20            return $this->me->value;   
21        }   
22    };   
23   
24        function &CreateObject($class_type)   
25        {   
26            switch ($class_type) {   
27                case "foo":   
28                    $obj =& new MyFoo();   
29                    break;   
30                case "bar":   
31                    $obj =& new MyBar();   
32                    break;   
33            }   
34            return $obj;   
35        }   
36   
37        $global_obj =& CreateObject ("foo");   
38        $global_obj->setValue(7);   
39   
40        print "Value is " . $global_obj->getValue() . "\n";   
41        print "Value is " . $global_obj->getValueFromMe() . "\n";  

PHP5是第一个把对象看成与其它类型数据不同的PHP版本. 从用户的角度看,这证明它非常明白的方式—在PHP5中,对象总是通过引用来传递,而其它类型数据(如integer,string,array)都是通过值来传递. 最显著地,没有必要再用&符号来表示通过引用来传递对象了.
面向对象编程广泛利用了对象网络和对象间的复杂关系,这些都需要用到引用. 在PHP的前些版本中,需要显示地指明引用. 因此, 现在默认用引用来移动对象,并且只有在明确要求复制时才复制对象,这样比以前更好.
它是如何实现的呢?
在PHP5之前,所有值都存在一个名为zval(Zend Value)的特殊结构里. 这些值可以存入简单的值,如数字和字符串,或复杂的值如数组和对象. 当值传给函数或从函数返回时,这些值会被复制,在内存的另一个地址建立一个带有相同内容的结构.
在PHP5中,值仍存为zval结构中,但对象除外. 对象存在一个叫做Object Store的结构里,并且每个对象有一个不同的ID. Zval中,不储存对象本身,而是存着对象的指针. 当复制一个持有对象的zval结构,例如我们把一个对象当成参数传给某个函数,我们不再复制任何数据. 我们仅仅保持相同的对象指针并由另一个zval通知现在这个特定的对象指向的Object Store. 因为对象本身位于Object Store,我们对它所作的任何改变将影响到所有持有该对象指针的zval结构.这种附加的间接作用使PHP对象看起来就像总是通过引用来传递,用透明和有效率的方式. 
使用PHP5,我们现在可以回到示例6.21,除去所有的&符号, 一切代码都仍然可以正常工作.当我们在构造函数(第4行)中持有一个引用时一个&符号都不用. 
PHP 相关文章推荐
用ADODB来让PHP操作ACCESS数据库的方法
Dec 31 PHP
php 记录进行累加并显示总时长为秒的结果
Nov 04 PHP
如何使用“PHP” 彩蛋进行敏感信息获取
Aug 07 PHP
PHP禁止个别IP访问网站
Oct 30 PHP
smarty模板引擎从php中获取数据的方法
Jan 22 PHP
Laravel 5框架学习之向视图传送数据(进阶篇)
Apr 08 PHP
PHP中in_array函数使用的问题与解决办法
Sep 11 PHP
php禁用cookie后session设置方法分析
Oct 19 PHP
PHP实现判断数组是一维、二维或几维的方法
Feb 06 PHP
yii2中dropDownList实现二级和三级联动写法
Apr 26 PHP
Laravel推荐使用的十个辅助函数
May 10 PHP
通过代码实例解析PHP session工作原理
Dec 11 PHP
第十四节--命名空间
Nov 16 #PHP
第十三节--对象串行化
Nov 16 #PHP
第十二节--类的自动加载
Nov 16 #PHP
第十一节--重载
Nov 16 #PHP
第十节--抽象方法和抽象类
Nov 16 #PHP
第九节--绑定
Nov 16 #PHP
第八节--访问方式
Nov 16 #PHP
You might like
模拟OICQ的实现思路和核心程序(一)
2006/10/09 PHP
Javascript学习笔记 delete运算符
2011/09/13 Javascript
extjs 3.31 TreeGrid实现静态页面加载json到TreeGrid里面
2013/04/02 Javascript
Javascript之this关键字深入解析
2013/11/12 Javascript
js中iframe调用父页面的方法
2014/10/30 Javascript
node.js中的fs.close方法使用说明
2014/12/17 Javascript
node.js中的fs.chmodSync方法使用说明
2014/12/18 Javascript
jQuery中的jQuery()方法用法分析
2014/12/27 Javascript
JS中innerHTML和pasteHTML的区别实例分析
2016/06/22 Javascript
js 动态生成html 触发事件传参字符转义的实例
2017/02/14 Javascript
js实现图片上传并预览功能
2018/08/06 Javascript
vue3.0 CLI - 3.2 路由的初级使用教程
2018/09/20 Javascript
详解vue 命名视图
2019/08/14 Javascript
JavaScript Dom实现轮播图原理和实例
2021/02/19 Javascript
[05:04]DOTA2上海特级锦标赛主赛事第二日TOP10
2016/03/04 DOTA
python执行子进程实现进程间通信的方法
2015/06/02 Python
详解Python中的元组与逻辑运算符
2015/10/13 Python
python字典快速保存于读取的方法
2018/03/23 Python
python自动化UI工具发送QQ消息的实例
2019/08/27 Python
Python实现FLV视频拼接功能
2020/01/21 Python
基于Python爬取爱奇艺资源过程解析
2020/03/02 Python
pycharm部署、配置anaconda环境的教程
2020/03/24 Python
Python Pandas 对列/行进行选择,增加,删除操作
2020/05/17 Python
五分钟带你搞懂python 迭代器与生成器
2020/08/30 Python
python对批量WAV音频进行等长分割的方法实现
2020/09/25 Python
一文读懂python Scrapy爬虫框架
2021/02/24 Python
利用CSS的Sass预处理器(框架)来制作居中效果
2016/03/10 HTML / CSS
Ted Baker英国官网:男士和女士服装及配件
2017/03/13 全球购物
荷兰皇家航空公司官方网站:KLM Royal Dutch Airlines
2017/12/07 全球购物
ddl,dml和dcl的含义
2016/05/08 面试题
最受欢迎的自我评价
2013/12/22 职场文书
财务情况说明书范文
2014/05/06 职场文书
关于孝道的演讲稿
2014/05/21 职场文书
人力资源职位说明书
2014/07/29 职场文书
车队安全员岗位职责
2015/02/15 职场文书
Java实现简易的分词器功能
2021/06/15 Java/Android