記事「The Truth of PHP4
」の著者 Johan Persson は、PHP の有名な JpGraph チャート ライブラリの開発者です。この記事は、PHP4 でオブジェクト指向開発を行う際に注意する必要があるいくつかの小さな問題を著者が要約したものです。 .
翻訳: Binzy Wu [メール: Binzy at JustDN dot COM]、限定レベル、議論歓迎 2004-2-4
はじめに
この記事は、より成熟した OO [1] 言語を使用したことのある人を対象としています。 Eiffel、Java、C# [2]、または C++()、開発中の友人 (私など) のように、PHP4 を使用して完全な OO 開発を行う場合、多くのセマンティック トラップ [3] (セマンティック)
[4] が存在します。この記事の内容が他の人に役立つことを願っています。私が犯した間違いを回避してください。
リファレンス VS コピー セマンティクス
これは、基本的に (少なくとも私にとっては) エラーの主な原因です。PHP ドキュメントでも、PHP4 がコピーを使用していることがわかります。参照 ( (私が知っている他のオブジェクト指向言語と同様) よりもセマンティクスが重要ですが、それでも、最終的には細かい点で悩むことになります。
次の 2 つの部分は、次の 2 つの小さな例を説明するために使用されます。驚かれるでしょう。
クラス変数はクラスへのポインターではなく、実際のクラスそのものであることを常に覚えておくことが重要です [5]。ほとんどの問題は、代入演算子 (=) に関する誤解から生じます。つまり、オブジェクトにエイリアスを与えているように見えますが、実際には新しいコピーです。たとえば、$myObj が特定のクラスのインスタンスであり、それに Set() メソッドがあるとします。プログラマーが期待するように C++ (または Java) が動作するようには見えません。 、それは簡単です。この関数によって呼び出される Set() メソッドが $myObj に作用すると思うでしょうが、これは間違いです!
実際、何が起こるかというと、$myObj は新しいもの、つまり、$myObj と同じコピーにコピーされます。元のオブジェクト----パラメータ $ aObj。その後、Set() メソッドが呼び出されるとき、元のパラメータ----$myObj ではなく、ローカル コピーに対してのみ動作します。
直接または間接的にさまざまな処理が行われます (上記と同様) 代入操作が含まれています 上記の問題
関数が期待どおり (おそらく) 動作するようにするには、次のようにメソッド宣言を変更して、参照を使用してオブジェクトを渡すように PHP に指示する必要があります。
Function SomeFunction(&$aObj)
上記のコードをもう一度試してみると、アクション内に $myObj のエイリアスを作成したので、Set() メソッドが元のパラメータに基づいて動作することがわかります。 --$aObj.
ただし、次の例のように、& 演算子でも常に保存できるわけではないので注意する必要があります。
参照から参照を取得する
次のコードがあるとします。
$myObject = new SomeClass();$ myRefToObject = &$myObject;
$myRefToObject なので、参照のコピーが必要な場合は、どうすればよいでしょうか?はすでに参照です:
$myRefToObject = $myRefToObject; いいえ、PHP は $myRefToObject によって参照されるオブジェクトの新しいコピーを作成します:
$myCopyRefToObject = &$myRefToObject;
with 前述の例は、PHP とは異なり、参照への参照を作成する C++ の例に対応しています。これは、PHP プログラムの場合に当てはまります。小規模および中規模のバグの原因です。
これによって引き起こされる間接的 (パラメーターの受け渡し) または直接的な問題に注意してください。
私の個人的な結論は、これらのセマンティック トラップを回避する最善の方法であるということです。これにより、実行時間が短縮される (データのコピーが減る) だけでなく、私のような老犬にとってセマンティクスがより予測しやすくなります
コンストラクターで $this への参照を使用します
オブジェクトのコンストラクター内で他のオブジェクト (Observer[6]) のディスカバーとして機能するオブジェクトを初期化するのが一般的なパターンです。次のコード行はその例です。
class Bettery
{
function Bettery() {… };
関数 AddObserver($method, &$obj)
{
$this->obs[] = array($obj, &$method)
}
関数 Notify(){…}
}
クラス Display
{
function Display(&$batt)
{
$batt->AddObserver("BatteryNotify",$this);
}
function BatteryNotify() {…}
}
ただし、次のようにオブジェクトをインスタンス化すると、これは正しく機能しません:
$myBattery = new Battery();$myDisplay = new Display($myBattery);
これを行う際のエラーは、new $ を使用する場合です。コンストラクター内の this は同じオブジェクトを返しません。代わりに、AddObserver() を呼び出すときに渡されたオブジェクトが元のオブジェクトと同じではありません。オブザーバーが (Notify メソッドを呼び出すことによって) すべてに通知するには、作成した Display クラスではなく、$this で表されるクラス (つまり、作成した Display クラスのコピー) を呼び出します。メソッドはいくつかのインスタンス変数を更新しますが、元の Display クラスが思ったように更新されるわけではありません。これが機能するためには、コンストラクターが元の $this シンボルと同じオブジェクトを返すようにする必要があります。 $myDisplay = & new Display($myBattery); のように & 記号を Display コンストラクターに追加できます。実際、これにより、Display クラスのクライアントは Display の実装の詳細を理解する必要があります。これは潜在的に物議を醸す問題を引き起こします: すべてのオブジェクト構築では追加のアンパサンドを使用する必要があります。前述したように、これは基本的に安全ですが、これを無視すると、上記の例のように望ましくない影響が生じる可能性があります。それは、&$this 参照をオブジェクトを「新規」に安全に使用できる「Init()」メソッドを追加することで、いわゆる 2 フェーズ構造を使用することです (コンストラクター内の $this 参照が を返すためです)。したがって、上記の例は次のように実装されます:
$myBattery = new Battery();
$myDisplay = new Display();
$ myDisplay->Init($myBattery) ;
JPGraph.php の "LinearScale" クラスなど。
foreach の使用
同様のコードだが結果が異なるもう 1 つの問題は、"foreach" 構造の問題です。次の 2 つのループの異なるバージョンです。 Structure.
// バージョン 1
foreach( $this->plots as $p )
{
$p->Update();
}
…
// バージョン 2
for( $i=0 ; $i
{
$this->plots[$i]->Update();
}
$10 の質問 [7] ]: version1==version2 ですか?
驚くべき答えは次のとおりです: いいえ! これは小さいですが重要な違いです。バージョン 1 では、Update() メソッドは "plots[]" 配列内のオブジェクトのコピーに作用します。したがって、配列内の元のオブジェクトは更新されません。
バージョン 2 では、Update() メソッドは、最初の部分で述べたように、「plots[]」配列内のオブジェクトに作用します。 、これは PHP がオブジェクト インスタンスをオブジェクト参照としてではなくオブジェクト自体として扱った結果です。
注釈:
[1]。OO: オブジェクト指向、オブジェクト指向。オリジナルには C# はありません。テキストはすべて Binzy の個人的な好みによるものです。
[3]。この記事では Semantic は「セマンティクス」と訳されています。ご提案があれば、Binzy までご連絡ください。C++ に関する有名な書籍「C++ Gotchas」があります。 ".
[5]。ここでのクラスは、インスタンスである Instance を参照する必要があります。
[6]。「デザイン パターン」である "[GoF95]" を参照してください。
[7]。非常に興味深いものがあります。取引に関する短い話: ある人が馬を 60 ドルで購入し、70 ドルで売りました。その後、彼はそれを 80 ドルで買い戻し、最終的には 90 ドルで売りました。馬の取引で、彼は 10 ドルを失いました。 (B) 損益分岐点、(D) は 20 ドル、(E) は 30 ドルです。
これはアメリカの秘密です。シカゴ大学の心理学者マイヤーとバークは、大学生に簡単な算数の問題を計算させました。その結果、正解できた大学生は 40% 未満であり、ほとんどの人は 10 ドルしか稼げないと考えていました。 10 ドルですが、多くの人は 80 ドルで買い戻したときに 10 ドル損をしたと誤解しています。興味深いことに、同じ質問が別の方法で行われました。ある人は 60 ドルで白い馬を購入し、その後 70 ドルで売りました。彼は黒い馬を 80 ドルで買い、それを 90 ドルで売りました。この馬の売買取引では、彼は ____ (同じ 5 つの選択肢をリストしました) この時点で、別の大学生のグループが上記の質問に答えたとき、全員が答えました。正解しました
http://www.bkjia.com/PHPjc/314503.html
www.bkjia.com
true
http://www.bkjia.com/PHPjc/314503.html