オブジェクト|php5
/*
+---------------------------------------------- -- ----------------------------------+
| この記事は Haohappy<
| = クラスとオブジェクトの章のメモ
| = 不必要なトラブルを避けるため、転載はご遠慮ください
| PHP 愛好家全員で一緒に進歩しましょう
+------------------------------------------ --------- ----------------------------------+
*/
セクション15--Zend エンジンの開発
この章の最後のセクションでは、Zend エンジンによってもたらされたオブジェクト モデルについて、特にそれが PHP の以前のバージョンのモデルとどのように異なるのかについて説明します。
1997 年の夏に PHP3 を開発したとき当時、PHP をオブジェクト指向にする計画はありませんでした。PHP3 は純粋な手続き型言語です。しかし、8 月の夜にクラスのサポートが追加されました。 1997 年 8 月 27 日。当時は PHP を研究する人が少なすぎたため、PHP に新しい機能を追加するのにほとんど議論は必要ありませんでした。そのため、1997 年 8 月から、PHP はオブジェクト指向プログラミング言語への第一歩を踏み出しました。
確かに、これは最初のステップにすぎません。この設計には関連するアイデアがほとんどないため、このバージョンでのオブジェクトの使用は、配列にアクセスするための優れた方法に過ぎません。 "bar ”] では、より見栄えの良い $foo->bar を使用できます。オブジェクト指向アプローチの主な利点は、メンバー関数またはメソッドを通じて機能を保存できることです。典型的なコード ブロックを例 6.18 に示します。例との違い 6.19 のアプローチは実際にはそれほど変わりません。
リスト 6.18 PHP 3 のオブジェクト指向プログラミング PHP3 のオブジェクト指向プログラミング
class 例
{
var $value = "some value";
関数 PrintValue ()
{
print $this->value;
}
}
$obj->PrintValue();
リスト 6.19 3 構造化プログラミング PHP3 の構造化プログラミング
function PrintValue($arr)
{
print $arr["value"];
}
function CreateExample()
{
$arr["value"] = "some value";
$arr["PrintValue"] = "PrintValue";
return $arr;
//PHP の間接参照を使用します
$arr["PrintValue" ]($arr);
?>
上記では、クラスに 2 行のコードを記述するか、配列を関数に明示的に渡しますが、PHP3 ではこれら 2 つのオプションに違いがないことを考慮すると、次のようになります。オブジェクト モデルを配列にアクセスするための「構文のホワイトウォッシュ」として扱うだけです
オブジェクト指向開発に PHP を使用したい人、特にデザイン パターンを使用したい人は、幸いなことに、すぐに壁にぶつかります。 (PHP3 時代には) オブジェクト指向開発に PHP を使いたいと思う人は多くありませんでした。
PHP4 では、PHP の異なる識別子が同じアドレスのメモリを指すことができるようにするため、この状況が変わりました。例 6.20 のように、2 つ以上の名前を使用して同じ変数に名前を付けることができることを意味します。 $a とメモリ内の同じ場所 $b と $a はメモリ内の同じアドレスを指します
$b = &$a
//$a が $b の変更を指しているため、$b を変更します変更点を指す
//同じ場所 - $a が指すアドレスも変更されます
$b = 7;
//prints 7 出力 7
print $a?>相互に参照するオブジェクトのネットワークを構築することはすべてのオブジェクト指向設計パターンの基礎ですが、この改善は非常に重要です。参照によってより強力なオブジェクト指向アプリケーションを作成できるようになりますが、PHP はオブジェクトを他の型に対しても同じアプローチで扱います。 PHP4 プログラマーなら誰でも言うように、アプリケーションは WTMA (アンパサンドが多すぎる) 症候群に悩まされることになります。実際のアプリケーションを構築する場合は、非常に苦痛に感じるでしょう。
リスト 6.21 PHP 4 のオブジェクトの問題
1 class MyFoo {
2 function MyFoo()
3 {
4 $this->me = &$this->
5 $this->値 = 5;
6 }
7
8 関数 setValue($val)
9 {
10 $this->値 = $val;
11 }
12
13 関数 getValue()
14 {
15 return $ this->値;
16 }
17
18 関数 getValueFromMe()
19 {
20 $this->me-> 値を返す
21 }
22 }
23
24 関数 CreateObject($class_type)
25 {
26 switch ($class_type) {
27 case "foo":
28 $obj = new MyFoo();
30 case "bar":
31 $obj = new MyBar(); 32 ブレーク;
33 }
34 return $obj;
36
37 $global_obj = CreateObject ("foo");38 $global_obj->setValue(7);
39
40 print "値は " . $global_obj->getValue() . "n"; . "n";
まず、MyFoo クラスに参照を与えて
他の 3 つのメンバーを設定します。 1 つは this->value の値を設定し、もう 1 つは this->value->me の値を返します。 MyFoo ::getValue() と MyFoo::getValueFromMe() によって返される値は同じではありませんか?
まず、MyFoo 型のオブジェクトを返す CreateObject("foo") を呼び出します。 MyFoo::setValue( 7) 最後に、MyFoo::getValue() と MyFoo::getValueFromMe() を呼び出し、戻り値 7 を取得することを期待します。
もちろん、いずれの場合でも 7 を取得した場合、上記の例は次のようになります。この本の意味の例では、もうおわかりかと思いますが、7 が 2 つも得られません
しかし、どのような結果が得られるのでしょうか? さらに重要なのは、なぜ得られるのでしょうか?それぞれ 7 つと 5 つです。理由については、3 つあります。まず、コンストラクター内で、this と this->me の間の参照を確立します。 - >me も同じですが、コンストラクターの内部にいます。コンストラクターが終了すると、PHP はオブジェクト (new MyFoo の 28 行目の結果) を再作成し、それを $obj に割り当てる必要があります。他のデータ型と同様に、X を Y に代入すると、Y は What about? のコピーであることを意味します。これは参照であるため、元のオブジェクト (つまり、this) を指します。それらはもはや同じものではありません。一方を変更しても、他方は変更されません。
上記は理由その 1 です。奇跡的に、オブジェクトのインスタンス化の問題を克服することになる理由は他にもあります。 28 行目) CreateObject によって返された値を global_object に代入しても、やはり同じ問題に遭遇する必要があります。問題は、global_object が戻り値のコピーになり、再度、global_object と global_object->me がコピーされなくなるということです。これが 2 番目の理由です
しかし、実際にはまだそこまではできません。CreateObject が $obj を返したら、これが 3 番目の理由です
。では、これを修正するにはどうすればよいでしょうか? 1 つは、例 6.22 (行 24、28、31、37) のように、あらゆる場所にアンパサンドを追加することです。幸運にも PHP5 を使用できる場合は、すべてを忘れることができます。上記のとおり、PHP5 がこれらの問題をどのように考慮するかを知りたい場合は、読み続けてください。
リスト 6.22 PHP 4 の WTMA シンドローム
1 class MyFoo {
2 function MyFoo()
3 {
4 $this->me = &$this;
5 $this->value = 2;
6 }
7
8 関数 setValue($val)
9 {
10 $this->値 = $val;
11 }
12
13 関数 getValue()
14 {
15 戻り値 $this->value;
16 }
17
18 関数 getValueFromMe()
19 {
20 戻り値 $this-> ;me->value;
21 }
22 };
23
24 関数 &CreateObject($class_type)
25 {
26 スイッチ ($class_type) {
27 case "foo":
28 $obj =& new MyFoo ();
29 ブレーク;
30 ケース "バー":
31 $obj = & new MyBar();
34 return $obj }
36
37 $global_obj; ("foo");
38 $global_obj->setValue(7);
39
40 print "値は " . $global_obj->getValue() . global_obj->getValueFromMe() . "n";
PHP5 は、オブジェクトを他のタイプのデータとは異なる方法で扱う最初の PHP バージョンであることがわかります。他のタイプのデータ (整数、文字列、配列など) はすべて値によって渡されますが、オブジェクト指向では、オブジェクトを参照によって渡すことを示すために & 記号を使用する必要がありません。プログラミングでは、参照が必要なオブジェクト ネットワークとオブジェクト間の複雑な関係が広範囲に使用されます。PHP の以前のバージョンでは、参照を明示的に指定する必要がありました。そのため、オブジェクトは明示的に要求された場合にのみコピーされます。
仕組みはどうですか?
PHP5 より前では、すべての値は zval (Zend Value) と呼ばれる特別な構造体に格納されていました。数値や文字列などの、または配列やオブジェクトなどの複雑な値を関数に渡すとき、または関数から値を返すとき、これらの値はコピーされ、メモリ内の別のアドレスに同じ内容の構造体が作成されます。
PHP5でも、オブジェクトを除いて値はzval構造体に格納されます。オブジェクトはオブジェクトストアと呼ばれる構造体に存在し、Zvalではオブジェクト自体は格納されませんが、オブジェクトのポインタが格納されます。オブジェクトを保持する zval 構造体をコピーする場合、たとえばオブジェクトを関数にパラメータとして渡す場合、データはコピーされなくなり、同じオブジェクト ポインタを保持し、オブジェクト ストアが指す別の zval から現在の特定のオブジェクトに通知します。オブジェクト自体はオブジェクト ストアに配置されているため、オブジェクトに加えた変更は、そのオブジェクトへのポインタを保持するすべての zval 構造に影響を及ぼし、PHP オブジェクトは常に透過的に参照されているかのように見えます。効率的な方法です。
PHP5 を使用して、例 6.21 に戻り、すべてのアンパサンドを削除しても、コンストラクター (4 行目) を保持しても問題なく動作します。
引用するときにアンパサンドを使用しないでください。