PHP は言語軽蔑の連鎖の最下位にあるものであるということがインターネット上でよく広まっています。私はかつて大学で Java を勉強していました。私も大学卒業後、研修のために Java を使用していましたが、最初の 2 ~ 3 年間は、PHP のオブジェクト指向の性質について常に感じていました。 JS に対する私の意見は言うまでもなく、「魚でも鳥でもない」でした。しかし、プロジェクトを重ねるごとに、こうした考えは徐々に薄れ、あるいは変化してきました。これには、プロジェクトとテクノロジーに対する理解を深めることが含まれますが、同時に、Web 環境とテクノロジーは長年にわたって常に更新されてきました。しかし、今日私はこれらのことについて話すためにここにいるわけではありません。私の視点は次のように要約できます。テクノロジーはツールであり、それが適切でない場合は、それをアップグレードするか置き換えるということです。 。
元の話題に戻ります。私は 8 年近く PHP の作成に熟練してきましたが、仕事の関係で、フロントエンドとバックエンドにさまざまなコードを関与させる必要があることが多く、分離しやすく、いつも忘れてしまいます。最近、書き留めておけば少しは目が覚めるかもしれないと思う出来事がありました。
ある年に、あるモジュールを書いたとき、静的メンバーを使っていたのですが、そのサブクラスを実装する過程で、親クラスのメンバーの値も共有していることに気づきました。具体的には、あるモジュールのメンバーの値を変更しました。サブクラス A. が別のサブクラス B によって使用されると、A によって上書きされた値が予期せず取得されました。その時思ったのですが、静的メンバは宣言箇所からカテゴリツリー全体で共有されることが分かりました。その後、この結論をうっすらと思い出し、作成したクラスが独立したツールクラスであることが確認できない限り、静的メンバーを安易に使用すべきではないと通常のコードで慎重に使用しました。
ある日、上司が私が以前に作成した BaseModel のアップグレードについて話し合うまで、彼は偶然私にこう尋ねました。「静的メンバーを使用するのが好きではないようですね?」いいえと答えたのは、BaseModel がさまざまな Model に継承されることが多いことを考慮すると、ここで static を使用すると、将来問題が発生しやすくなるからです。彼は理解できないと言って、私のところに来て議論しました。静的メンバーは共有されるため、2 つの異なるサブクラスが呼び出された場合、静的メンバーの変数の値はグローバル変数と同様に制御不能になると正しく説明しました。彼は同意しません。そこで、科学の精神に従って、検証するための短いコードを書きました:
クラスA {
protected static $var1 = null;
パブリック静的関数 test(){
get_called_class()をエコーします。 ' '.static::$var1.'
';
}
}
クラス B は A を拡張します {
protected static $var1 = 'b';
}
クラス C は A を拡張します {
protected static $var1 = 'c';
}
B::test();
C::test();
今回は当然負けました。 結果は c c と予想していましたが、実際は b c でした。 したがって、サブクラスの静的メンバーはサブクラス レベルでのみ共有されるようです。しかし、私はいつも何かが間違っていると感じます。BaseModel を作成していたときに、明らかに別の挫折がありました。なぜこの検証では、そのときに遭遇した問題がサポートされないのでしょうか。その時、私は何かを忘れていることに気づきました。若いのはなんて素晴らしいことでしょう。後で考えてみると、ここで static を使用しなかったのは、単に設計要件のためでした。
私は間違っていると思いました。数日前まで、(BaseModelではなく)さらにいくつかの親子クラスを作成し、静的メンバーを大胆に使用した結果、セルフテストで再びつまずきました。どうしたの!次に、今回は使用法に細心の注意を払い、上記の例を変更して実行しました:
クラスA {
protected static $var1 = null;
protected static $var2 = null;
パブリック静的関数 test(){
if(!static::$var2){
static::$var2 = static::$var1;
}
get_called_class()をエコーします。 ' '.static::$var1.'
';
}
}
クラス B は A を拡張します {
protected static $var1 = 'b';
}
クラス C は A を拡張します {
protected static $var1 = 'c';
}
B::test();
C::test();
結果は
B b
Cb
前回の結論が正しかったとしたら、今回はどう説明しますか?これは明らかに、$var2 が A、B、C によって共有されていることを意味します。 $var1 と $var2 の違いは、宣言されているかどうかの違いだけのようです。そこで私はこれを次のように変更しました:
クラスA {
protected static $var1 = null;
protected static $var2 = null;
パブリック静的関数 test(){
if(!static::$var2){
static::$var2 = static::$var1;
}
get_called_class()をエコーします。 ' '.static::$var1.'
';
}
}
クラス B は A を拡張します {
protected static $var1 = 'b';
protected static $var2 = null;
}
クラス C は A を拡張します {
protected static $var1 = 'c';
protected static $var2 = null;
}
B::test();
C::test();
結果は
B b
Cc
私は内心打ち砕かれました。そこで Stack Overflow に行ってみると、騙されたのは私だけではないことがわかりました。
明示的に宣言された静的メンバーのみが、サブクラスにのみ属しているとみなされます。
明示的に宣言された静的メンバーのみがサブクラスにのみ属するとみなされます。
明示的に宣言された静的メンバーのみが、サブクラスにのみ属しているとみなされます。
大事なことは3回言いましょう!ただし、サブクラスの数が多い場合、値が動的に決まる各メンバーがこのように宣言されることになり、コードを書く上で static を使う意味がなくなってしまいます。より良い方法は、$var2 を配列にして、各クラスで使用される値を $var[__CLASS__] に入れることです。
ただし、どうしても必要でない場合は、静的メンバーの継承は使わないようにしましょう。
ちょっと似たような「穴」がもう一つあります。プライベート メンバーについて話すとき、プライベートとはプライベートを意味し、サブクラスには継承されないことは誰もが知っています。しかし、コードを書いているときに忘れてしまうこともあり、書き始めるまで思い出せないことがあります。その理由は、サブクラスが持つべきメンバーを見つけられない原因であることが判明したり、サブクラスで private が宣言されていることが判明したりするためです。関数を呼び出すと、親クラス関数が呼び出され、結果はサブクラスではなく親クラスのプライベート値になります。この場合、サブクラス内の関数をそのまま書き換えることはできません。したがって、プライベートを使用する場合は十分に注意してください。
Rackspace の SDK を使用していたときに、一部のクラスでプライベート メンバーが使用されていることがわかりましたが、ファイルを開くための不要なアクセス許可を与えたため、コードはサーバー上で実行できませんでした。なのでこの時はこのメンバの初期値を上書きするサブクラスを書きたかったのですが、結局プライベートメンバなので参照先を全て自分が書いたサブクラスにコピーする必要がありました。 SDK を変更してメンバーを保護するだけではどうでしょうか?次回開発パッケージがアップグレードされるかもしれないから?修正後はサブクラスを削除するだけです。ライブラリのコードを変更することが習慣になると、アップグレードするときにあまり楽しくなくなります。したがって、プライベート メンバーは注意して使用する必要があります。SDK も開発している場合は、ユーザーが継承する必要があるかどうかを考慮する必要があります。 private を記述する必要がある場合、そのコードがさまざまなシナリオで使用できることを確認できますか?
よほどの理由がない限り、静的とプライベートの両方を注意して使用する必要があります。