PHPではクラスのメンバー変数のことをプロパティ(プロパティ)とも言います。これらはクラス定義の一部であり、インスタンスの状態を表すために (つまり、クラスの異なるインスタンスを区別するために) 使用されます。具体的な実践では、属性の読み取りと書き込みに少し特殊なメソッドを使用したいことがよくあります。たとえば、ラベル属性に対して毎回トリム操作を実行する必要がある場合は、次のコードを使用してそれを実現できます:
リーリー上記のコードの欠点は、ラベル属性が変更されるたびに、trim() 関数を再度呼び出す必要があることです。将来、最初の文字を大文字にするなど、他の方法でラベル属性を処理する必要がある場合は、ラベル属性に値を割り当てるすべてのコードを変更する必要があります。このコードの重複はバグを引き起こす可能性があるため、この行為は可能な限り避ける必要があることは明らかです。
この問題を解決するために、Yii は yiibaseObject と呼ばれる基本クラスを導入します。これは、クラス内のゲッターおよびセッター (リーダーおよびセッター) メソッドに基づくプロパティの定義をサポートします。クラスがこの機能をサポートする必要がある場合、yiibaseObject またはそのサブクラスを継承するだけで済みます。
補足: Yii フレームワークのほぼすべてのコアクラスは、yiibaseObject またはそのサブクラスを継承します。これは、コア クラスでゲッター メソッドまたはセッター メソッドを見つけたときはいつでも、プロパティと同じように呼び出すことができることを意味します。
ゲッター メソッドは名前が get で始まるメソッドであり、セッター メソッド名は set で始まります。メソッド名の get または set 以降の部分は、プロパティの名前を定義します。以下のコードに示すように、ゲッター メソッド getLabel() とセッター メソッド setLabel() はラベル属性を操作します。
リーリー
ゲッター/セッターで定義された属性の使用法は、クラスのメンバー変数と同じです。 2 つの主な違いは、このプロパティが読み取られると、対応するゲッター メソッドが呼び出され、プロパティに値が割り当てられると、対応するセッター メソッドが呼び出されることです。例:
リーリー
ゲッターのみが定義され、セッターが定義されていないプロパティは読み取り専用プロパティです。このようなプロパティに割り当てようとすると、yiibaseInvalidCallException (無効な呼び出し) 例外が発生します。同様に、ゲッター メソッドを使用せずにセッター メソッドのみで定義されたプロパティは書き込み専用プロパティであり、そのようなプロパティを読み取ろうとした場合も例外がトリガーされます。書き込み専用属性を使用するケースはほとんどありません。ゲッターとセッターを介して定義されたプロパティには、いくつかの特別なルールと制限もあります:
そのような属性の名前では大文字と小文字が区別されません。たとえば、$object->label と $object->Label は同じプロパティです。 PHP メソッド名では大文字と小文字が区別されないためです。
このような属性の名前がクラス メンバー変数の名前と同じ場合は、後者が優先されます。たとえば、上記の Foo クラスに label メンバー変数があり、$object->label = 'abc' に値を割り当てると、セッター setLabel() メソッドの代わりにメンバー変数に割り当てられるとします。
このタイプのプロパティでは、可視性 (アクセス制限) はサポートされていません。プロパティの getter メソッドと setter メソッドが public、protected、または private であるかどうかは、プロパティの可視性には影響しません。
このようなプロパティのゲッター メソッドとセッター メソッドは非静的としてのみ定義でき、静的メソッド (静的) として定義されている場合、同じように処理されません。
最初に述べた質問に戻りますが、trim() 関数をどこでも呼び出すのではなく、setter setLabel() メソッド内で 1 回呼び出すだけで済みます。ラベルの最初の文字を大文字にするという新しい要件が発生した場合は、他のコードには触れずに setLabel() メソッドを変更するだけで済みます。
属性を実装する手順
オブジェクトの存在しないメンバー変数を読み書きする場合、__get() __set() が自動的に呼び出されることはわかっています。 Yii はこれを利用して属性のサポートを提供します。上記のコードから、オブジェクトのプロパティにアクセスすると、Yii が getpropertyname() という関数を呼び出すことがわかります。たとえば、SomeObject->Foo は SomeObject->getFoo() を自動的に呼び出します。プロパティが変更されると、対応するセッター関数が呼び出されます。 たとえば、SomeObject->Foo = $someValue は SomeObject->setFoo($someValue) を自動的に呼び出します。したがって、プロパティを実装するには、通常 3 つのステップがあります:
リーリー
理論的には、private $_titleをpublic $titleとして記述することで、$post->titleの読み書きも可能になります。しかし、これは次の理由から良い習慣とは言えません:クラスのカプセル化が失われました。 一般に、メンバー変数を外部から見えないようにすることは、良いプログラミング方法です。 ここからは表示されないかもしれませんが、いつかユーザーにタイトルを変更させたくない場合、どうすれば変更できますか? タイトルがコード内で直接変更されないようにする方法は? セッターが提供されている場合、そのセッターが削除されている限り、ヘッダーへの未クリーンな書き込みがあると例外がスローされます。 public $titleメソッドを使用している場合、private $titleに変更することで書き込み例外を確認できますが、読み出しも禁止されます。
タイトルを書く場合、スペースを削除したいとします。 setter メソッドを使用すると、上記のコード スニペットのように、この場所で trim() を呼び出すだけで済みます。 ただし、パブリック $title メソッドを使用する場合は、write ステートメントごとに trim() が呼び出されるのは間違いありません。 何も欠けていないことを保証できますか?
したがって、public $title を使用するのは手っ取り早いだけで簡単そうに見えますが、後々修正するのが面倒になります。 それは悪夢と言ってもいい。これがソフトウェア エンジニアリングの意味であり、特定の方法でコードの保守と変更を容易にします。 一見不必要に思えるかもしれませんが、実際、損失を被った友人や、クライアントの上司から前のプログラマーが書いたコードの修正を強要され、親戚に挨拶した友人は皆、これが非常に必要だと感じるでしょう。
しかし、この世に絶対はありません。 __get() と __set() はすべてのメンバー変数を調べられるため、一致するメンバー変数が見つからない場合にのみ呼び出されます。 したがって、その効率はメンバー変数を使用する場合よりも本質的に低くなります。データ構造、データ コレクションなどが表現され、読み取り/書き込み制御が必要ない単純な状況では、効率を向上させるためにメンバー変数を属性として使用することを検討できます。
効率を向上させるためのもう 1 つの小さなトリックは、$pro = $object->pro の代わりに $pro = $object->getPro() を使用し、$object-> の代わりに $objcect->setPro($value) を使用することです。 ;pro = $value 。 これは機能的にはまったく同じですが、__get() と __set() の使用を回避します。これは、トラバーサル プロセスをバイパスするのと同じです。
ここで誰かが私を叱るべきかもしれませんが、Yii は開発者を容易にするためだけに属性メカニズムを実装しましたが、私はここで、いわゆる効率を向上させるためのオリジナルのメソッドの使用方法を教えます。 確かに、開発の利便性と実行の高い効率の間には、ある種の矛盾があります。私の個人的な考え方としては、利便性を第一に考え、Yii が作り出した便利な条件を有効に活用したいと考えています。効率に関しては、フレームワーク自体がもっと注意を払う必要がありますが、余分なコードを書かない限りは問題ありません。
しかし、Yii フレームワークでは $app->request のようなコードはほとんど出現せず、代わりに $app->getRequest() が使用されるのでご安心ください。 つまり、フレームワーク自体は効率性を重視しており、利便性は開発者に委ねられています。 つまり、ここで紹介するのは単なる知識であり、それを使用するかどうか、どのように使用するかは完全にあなた次第です。
注目すべき点:
__get() __set() が自動的に呼び出されるタイミングは、存在しないメンバ変数にアクセスする場合のみなので。 したがって、メンバ変数 public $title が定義されている場合、getTitle() setTitle() が定義されていても呼び出されません。 $post->title は直接 $title を指すため、 __get() __set() は呼び出されません。根元から切り離されてしまいました。
PHP ではクラス メソッドの大文字と小文字が区別されないため、$post->getTitle() と $post->gettitle() は同じ関数を呼び出します。 したがって、$post->title と $post->Title は同じプロパティです。つまり、属性名でも大文字と小文字は区別されません。
__get() と __set() は両方とも public であるため、getTitle() setTitle() が public、private、または protected として宣言されているかどうかは意味がありません。また、外部からアクセスすることもできます。したがって、すべてのプロパティは公開されます。
__get() も __set() も静的ではないため、静的属性を使用する方法はありません。
Object のその他のプロパティ関連メソッド
__get() __set() に加えて、yiibaseObject は属性の使用を容易にする次のメソッドも提供します。
yiibaseComponent は yiibaseObject を継承しているため、プロパティなどの基本的な機能も備えています。
ただし、Componentではイベントやビヘイビアも導入しているため、単にObjectのプロパティ実装メソッドを継承するのではなく、同じ仕組みに基づいて __get() __set() などの関数をオーバーロードします。ただし、実装メカニズムの点では、それらは同じです。これは理解には影響しません。
前述したように、Yii は公式にはコンポーネントベースのフレームワークとして位置付けられています。可視コンポーネントの概念は Yii の基礎です。 Yii のソースコードまたは API ドキュメントを読むことに興味がある場合は、Yii のほぼすべてのコアクラスが yiibaseComponent から派生 (継承) されていることがわかります。
Yii1.1 にはすでにコンポーネントがあり、当時は CComponent でした。 Yii2 は、Yii1.1 の CComponent を 2 つのクラス、yiibaseObject と yiibaseComponent に分割します。
その中で、Object は比較的軽量であり、ゲッターとセッターを通じてクラスのプロパティを定義します。コンポーネントはオブジェクトから派生し、イベントと動作をサポートします。したがって、Component クラスには 3 つの重要な特性があります:
この3つの特徴が、学級機能の充実・拡充や学級行動の変革に向けた重要な入り口であることは、ある程度ご理解いただけたと思います。 したがって、コンポーネントは Yii において非常に高い地位を占めています。
コンポーネントは、より多くの機能と利便性を提供すると同時に、イベントと動作の 2 つの機能を追加しました。これにより、効率はある程度犠牲になりますが、開発が容易になります。 何らかのデータを表すクラスなど、開発中にイベントとビヘイビアの 2 つの機能を使用する必要がない場合。 すると、Componentからの継承はできず、Objectからの継承となります。 一般的なアプリケーション シナリオでは、ユーザーが入力したデータのセットを表す場合はオブジェクトを使用します。 そして、処理に応答できるオブジェクトやイベントの動作を処理する必要がある場合は、コンポーネントを使用する必要があることは間違いありません。 効率の点では、Object の方がネイティブ PHP クラスに近いため、可能な場合は Object を最初に使用する必要があります。