程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> 第十五節--Zend引擎的發展 -- Classes and Objects in PHP5 [15]

第十五節--Zend引擎的發展 -- Classes and Objects in PHP5 [15]

編輯:關於PHP編程

第十五節--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 PHPs 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; 



   //were 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() . "
"; 

41        print "Value is " . $global_obj->getValueFromMe() . "
"; 




讓我們一步步來討論. 首先,有一個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() . "
"; 

41        print "Value is " . $global_obj->getValueFromMe() . "
"; 



PHP5是第一個把對象看成與其它類型數據不同的PHP版本. 從用戶的角度看,這證明它非常明白的方式—在PHP5中,對象總是通過引用來傳遞,而其它類型數據(如integer,string,array)都是通過值來傳遞. 最顯著地,沒有必要再用&符號來表示通過引用來傳遞對象了.

面向對象編程廣泛利用了對象網絡和對象間的復雜關系,這些都需要用到引用. 在PHP的前些版本中,需要顯示地指明引用. 因此, 現在默認用引用來移動對象,並且只有在明確要求復制時才復制對象,這樣比以前更好.

它是如何實現的呢?

在PHP5之前,所有值都存在一個名為zval(Zend Value)的特殊結構裡. 這些值可以存入簡單的值,如數字和字符串,或復雜的值如數組和對象. 當值傳給函數或從函數返回時,這些值會被復制,在內存的另一個地址建立一個帶有相同內容的結構.
<

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved