PHP5.0对象模型探索之Zend引擎的发展
在这个系列文章的最后一部分,作者讨论了Zend引擎带来的对象模型,特别提到它与PHP的前几个版本中的模型有什么不同。
当1997年夏天,发布的PHP3中没有计划要使PHP具备面向对象的能力. 当时没有任何与类和对象有关的想法. PHP3是一个纯粹面向过程的语言. 但是,在1997.8.27的晚上PHP3 alpha版中增加了对类的支持. 增加一个新特性给PHP,当时仅需要极少的讨论,因为当时探索PHP的人太少. 于是从1997年八月起, PHP迈出了走向面向对象编程语言的第一步.
确实,这只是第一步. 因为在这个设计中只有极少的相关的想法,对于对象的支持不够强大. 这个版本中使用对象仅是访问数组的一个很酷的方法而已. 取代使用$foo[“bar”],你可以使用看起来更漂亮的$foo->bar. 面向对象方法的主要的优势是通过成员函数或方法来储存功能. 例子1中显示了一个典型的代码块. 但是它和例6.19中的做法其实并没有太大不同.
Listing1 PHP 3 object-oriented programming PHP3中的面向对象编程
{
var $value = "some value";
function PrintValue()
{
print $this->value;
}
}
$obj = new Example();
$obj->PrintValue();
?>
Listing2 PHP 3 structural programming PHP3 PHP3中的结构化编程
{
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的不同标识符指向内存中的同一个地址. 这意味着你可以使用两个或更多的名称来给同一个变量命名,就像例3那样.
Listing3 PHP 4 references PHP4中的引用
//$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过多&)综合症. 如果你想构建一个实际应用,你会感到极为痛苦,看看例3你就明白.
Listing3 Problems with objects in PHP 4 PHP4中使用对象的问题
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行) . 这就是第三条理由。
那么,我们如何改正这些? 有两个选择:一是在所有地方增加&符号,就像例4那样(第24, 28, 31, 37行)。二.如果你幸运地使用上了PHP5,你可以忘了以上这一切,PHP5会自动为你考虑这些。如果你想知道PHP5是如何考虑这些问题的,继续阅读下去。
Listing4 WTMA syndrome in PHP 4 PHP4中的WTMA综合症
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,我们现在可以回到示例3,除去所有的&符号, 一切代码都仍然可以正常工作。当我们在构造函数(第4行)中持有一个引用时一个&符号都不用。

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

function是函數的意思,是一段具有特定功能的可重複使用的程式碼區塊,是程式的基本組成單元之一,可以接受輸入參數,執行特定的操作,並傳回結果,其目的是封裝一段可重複使用的程式碼,提高程式碼的可重複使用性和可維護性。

在本文中,我們將了解enumerate()函數以及Python中「enumerate()」函數的用途。什麼是enumerate()函數? Python的enumerate()函數接受資料集合作為參數並傳回一個枚舉物件。枚舉物件以鍵值對的形式傳回。 key是每個item對應的索引,value是items。語法enumerate(iterable,start)參數iterable-傳入的資料集合可以作為枚舉物件傳回,稱為iterablestart-顧名思義,枚舉物件的起始索引由start定義。如果我們忽

MySQL.proc表的功能與功能詳解MySQL是一種流行的關係型資料庫管理系統,開發者在使用MySQL時常常會涉及到預存程序(StoredProcedure)的建立與管理。而MySQL.proc表則是一個非常重要的系統表,它儲存了資料庫中所有的預存程序的相關信息,包括預存程序的名稱、定義、參數等。在本文中,我們將詳細解釋MySQL.proc表的作用與功能

同事因為this指向的問題卡住的bug,vue2的this指向問題,使用了箭頭函數,導致拿不到對應的props。當我跟他介紹的時候他竟然不知道,隨後也刻意的看了一下前端交流群,至今最起碼還有70%以上的前端程式設計師搞不明白,今天給大家分享一下this指向,如果啥都沒學會,請給我一個大嘴巴子。

Vue.use函數的用法和作用Vue是一款流行的前端框架,它提供了許多有用的功能和功能。其中之一就是Vue.use函數,它可以讓我們在Vue應用中使用插件。本文將介紹Vue.use函數的用法和作用,並且提供一些程式碼範例。 Vue.use函數的基本用法非常簡單,只需在Vue實例化之前呼叫它,並傳入要使用的插件作為參數。以下是一個簡單的範例://引入並使用插件

這篇文章帶大家解讀vue原始碼,來介紹一下Vue2中為什麼可以使用 this 存取各種選項中的屬性,希望對大家有幫助!

js函數function用法有:1、宣告函數;2、呼叫函數;3、函數參數;4、函數回傳值;5、匿名函數;6、函數為參數;7、函數作用域;8、遞歸函數。

file_exists方法檢查檔案或目錄是否存在。它接受要檢查的檔案或目錄的路徑作為參數。以下是它的用途-當您需要在處理之前知道文件是否存在時,它非常有用。這樣,在建立新檔案時使用此函數即可知道該檔案是否已存在。語法file_exists($file_path)參數file_path-設定要檢查是否存在的檔案或目錄的路徑。必需。返回file_exists()方法返回。如果檔案或目錄存在,則傳回TrueFalse,如果檔案或目錄不存在範例讓我們看一個檢查「candidate.txt」檔案和即使文件
