在这个系列文章的最后一部分,作者讨论了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 では、オブジェクトは常に参照によって渡されますが、他のタイプのデータ (整数、最も注目すべき点は、オブジェクトを参照によって渡すことを示すために & 記号を使用する必要がないことです。オブジェクト指向プログラミングでは、オブジェクト ネットワークとオブジェクト間の複雑な関係が必要になります。参照の使用 以前のバージョンの PHP では、参照を明示的に指定する必要がありました。したがって、参照によるオブジェクトの移動がデフォルトになり、明示的に要求された場合にのみオブジェクトがコピーされるようになり、以前よりも改善されました。
どのように実装されていますか?
PHP5 より前では、すべての値は zval (Zend Value) と呼ばれる特別な構造体に格納されていました。これらの値は、次のような単純な値に格納できます。数値や文字列、あるいは配列やオブジェクトなどの複雑な値。値が関数に渡されるとき、または関数から返されるときに、値がコピーされ、メモリ内の別のアドレスに同じ内容の構造体が作成されます。
PHP5でも、オブジェクトを除いて値はzval構造体に格納されます。オブジェクトはオブジェクトストアと呼ばれる構造体に存在し、各オブジェクトは異なるIDを持ちます。Zvalではオブジェクト自体は格納されません。代わりに、オブジェクトへのポインタを保持します。たとえば、オブジェクトを関数にパラメータとして渡す場合、同じオブジェクト ポインタを保持して渡すだけです。別の zval へ この特定のオブジェクトが現在指していることをオブジェクト ストアに通知します。オブジェクト自体はオブジェクト ストアにあるため、これに加えた変更は、そのオブジェクトへのポインタを保持するすべての zval 構造に影響します。
PHP5 を使用して、例 3 に戻り、すべてのアンパサンドを削除しても、すべて正常に動作します。コンストラクターで参照を保持する場合 (4 行目)、アンパサンドはありません。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

SecLists
SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。

PhpStorm Mac バージョン
最新(2018.2.1)のプロフェッショナル向けPHP統合開発ツール

DVWA
Damn Vulnerable Web App (DVWA) は、非常に脆弱な PHP/MySQL Web アプリケーションです。その主な目的は、セキュリティ専門家が法的環境でスキルとツールをテストするのに役立ち、Web 開発者が Web アプリケーションを保護するプロセスをより深く理解できるようにし、教師/生徒が教室環境で Web アプリケーションを教え/学習できるようにすることです。安全。 DVWA の目標は、シンプルでわかりやすいインターフェイスを通じて、さまざまな難易度で最も一般的な Web 脆弱性のいくつかを実践することです。このソフトウェアは、

Dreamweaver Mac版
ビジュアル Web 開発ツール

ドリームウィーバー CS6
ビジュアル Web 開発ツール
