ホームページ  >  記事  >  バックエンド開発  >  PHP の Yii フレームワークのプロパティ

PHP の Yii フレームワークのプロパティ

小云云
小云云オリジナル
2017-11-13 11:50:281247ブラウズ

Yii は、大規模な Web アプリケーションを開発するための高性能コンポーネントベースの PHP フレームワークです。 Yii は厳密な OOP で書かれており、完全なライブラリ リファレンスと包括的なチュートリアルが含まれています。 MVC、DAO/ActiveRecord、ウィジェット、キャッシュ、階層型 RBAC、Web サービスからテーマ、I18N および L10N まで、Yii は今日の Web 2.0 アプリケーション開発に必要なほぼすべてを提供します。実際、Yii は最も効率的な PHP フレームワークの 1 つです。

Yii は、高性能 PHP5 Web アプリケーション開発フレームワークです。シンプルなコマンド ライン ツール yiic を使用すると、Web アプリケーション コード フレームワークを迅速に作成でき、開発者は生成されたコード フレームワークに基づいてビジネス ロジックを追加して、アプリケーション開発を迅速に完了できます。

PHPでは、クラスのメンバー変数はプロパティとも呼ばれます。これらはクラス定義の一部であり、インスタンスの状態を表すために (つまり、クラスの異なるインスタンスを区別するために) 使用されます。具体的な実践では、属性の読み取りと書き込みに少し特殊なメソッドを使用したいことがよくあります。たとえば、毎回ラベル属性に対してトリム操作を実行する必要がある場合は、次のコードを使用してそれを実現できます:

$object->label = trim($label);

上記のコードの欠点は、ラベル属性が変更されている限り、トリム( ) 関数を再度呼び出す必要があります。将来、最初の文字を大文字にするなど、他の方法でラベル属性を処理する必要がある場合は、ラベル属性に値を割り当てるすべてのコードを変更する必要があります。このコードの重複はバグを引き起こす可能性があるため、この行為は可能な限り避ける必要があることは明らかです。

この問題を解決するために、Yii は yiibaseObject と呼ばれる基本クラスを導入します。これは、クラス内のゲッターおよびセッター (リーダーおよびセッター) メソッドに基づくプロパティの定義をサポートします。クラスがこの機能をサポートする必要がある場合、yiibaseObject またはそのサブクラスを継承するだけで済みます。

補足: Yii フレームワークのほぼすべてのコアクラスは、yiibaseObject またはそのサブクラスを継承します。これは、コア クラスでゲッター メソッドまたはセッター メソッドを見つけたときはいつでも、プロパティと同じように呼び出すことができることを意味します。
ゲッター メソッドは名前が get で始まるメソッドであり、セッター メソッド名は set で始まります。メソッド名の get または set 以降の部分は、プロパティの名前を定義します。以下のコードに示すように、ゲッター メソッド getLabel() とセッター メソッド setLabel() は、ラベル属性を操作します:

namespace app\components;
use yii\base\Object;
class Foo extend Object
{
  private $_label;
  public function getLabel()
  {
    return $this->_label;
  }
  public function setLabel($value)
  {
    $this->_label = trim($value);
  }
}

(詳細説明: ゲッター メソッドとセッター メソッドは、label という名前の属性を作成します。この例では、それはポイントです)

ゲッター/セッターで定義されたプロパティは、クラスのメンバー変数と同じように使用されます。 2 つの主な違いは、このプロパティが読み取られると、対応するゲッター メソッドが呼び出され、プロパティに値が割り当てられると、対応するセッター メソッドが呼び出されることです。例:

// 等效于 $label = $object->getLabel();
$label = $object->label;
// 等效于 $object->setLabel('abc');
$object->label = 'abc';

ゲッターのみを定義し、セッターを定義しないプロパティは読み取り専用プロパティです。このようなプロパティに割り当てようとすると、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 つの手順があります:

yiibaseObject から継承します。

このプロパティを保存するには、プライベート メンバー変数を宣言します。

上記のプライベート メンバー変数にアクセスして変更するためのゲッター関数またはセッター関数、あるいはその両方を提供します。 ゲッターのみが提供されている場合、プロパティは読み取り専用であり、セッターのみが提供されている場合、プロパティは書き込み専用です。

次の Post クラスは、読み取りおよび書き込み可能な属性 title を実装します:

class Post extends yii\base\Object  // 第一步:继承自 yii\base\Object
{
  private $_title;         // 第二步:声明一个私有成员变量
  public function getTitle()    // 第三步:提供getter和setter
  {
    return $this->_title;
  }
  public function setTitle($value)
  {
    $this->_title = trim($value);
  }
}

从理论上来讲,将 private $_title 写成 public $title ,也是可以实现对 $post->title 的读写的。但这不是好的习惯,理由如下:

失去了类的封装性。 一般而言,成员变量对外不可见是比较好的编程习惯。 从这里你也许没看出来,但是假如有一天,你不想让用户修改标题了,你怎么改? 怎么确保代码中没有直接修改标题? 如果提供了setter,只要把setter删掉,那么一旦有没清理干净的对标题的写入,就会抛出异常。 而使用 public $title 的方法的话,你改成 private $title 可以排查写入的异常,但是读取的也被禁止了。
对于标题的写入,你想去掉空格。 使用setter的方法,只需要像上面的代码段一样在这个地方调用 trim() 就可以了。 但如果使用 public $title 的方法,那么毫无疑问,每个写入语句都要调用 trim() 。 你能保证没有一处遗漏?
因此,使用 public $title 只是一时之快,看起来简单,但今后的修改是个麻烦事。 简直可以说是恶梦。这就是软件工程的意义所在,通过一定的方法,使代码易于维护、便于修改。 一时看着好像没必要,但实际上吃过亏的朋友或者被客户老板逼着修改上一个程序员写的代码,问候过他亲人的, 都会觉得这是十分必要的。

但是,世事无绝对。由于 __get() 和 __set() 是在遍历所有成员变量,找不到匹配的成员变量时才被调用。 因此,其效率天生地低于使用成员变量的形式。在一些表示数据结构、数据集合等简单情况下,且不需读写控制等, 可以考虑使用成员变量作为属性,这样可以提高一点效率。

另外一个提高效率的小技巧就是:使用 $pro = $object->getPro() 来代替 $pro = $object->pro , 用 $objcect->setPro($value) 来代替 $object->pro = $value 。 这在功能上是完全一样的效果,但是避免了使用 __get() 和 __set() ,相当于绕过了遍历的过程。

这里估计有人该骂我了,Yii好不容易实现了属性的机制,就是为了方便开发者, 结果我却在这里教大家怎么使用原始的方式,去提高所谓的效率。 嗯,确实,开发的便利性与执行高效率存在一定的矛盾。我个人的观点更倾向于以便利为先, 用好、用足Yii为我们创造的便利条件。至于效率的事情,更多的是框架自身需要注意的, 我们只要别写出格外2的代码就OK了。

不过你完全可以放心,在Yii的框架中,极少出现 $app->request 之类的代码,而是使用 $app->getRequest() 。 换句话说,框架自身还是格外地注重效率的,至于便利性,则留给了开发者。 总之,这里只是点出来有这么一个知识点,至于用不用,怎么用,完全取决于你了。

值得注意的是:

由于自动调用 __get() __set() 的时机仅仅发生在访问不存在的成员变量时。 因此,如果定义了成员变量 public $title 那么,就算定义了 getTitle() setTitle() , 他们也不会被调用。因为 $post->title 时,会直接指向该 pulic $title , __get() __set() 是不会被调用的。从根上就被切断了。
由于PHP对于类方法不区分大小写,即大小写不敏感, $post->getTitle() 和 $post->gettitle() 是调用相同的函数。 因此, $post->title 和 $post->Title 是同一个属性。即属性名也是不区分大小写的。
由于 __get() __set() 都是public的, 无论将 getTitle() setTitle() 声明为 public, private, protected, 都没有意义,外部同样都是可以访问。所以,所有的属性都是public的。
由于 __get() __set() 都不是static的,因此,没有办法使用static 的属性。
Object的其他与属性相关的方法

除了 __get() __set() 之外, yii\base\Object 还提供了以下方法便于使用属性:

__isset() 用于测试属性值是否不为 null ,在 isset($object->property) 时被自动调用。 注意该属性要有相应的getter。

__unset() 用于将属性值设为 null ,在 unset($object->property) 时被自动调用。 注意该属性要有相应的setter。

hasProperty() 用于测试是否有某个属性。即,定义了getter或setter。 如果 hasProperty() 的参数 $checkVars = true (默认为true), 那么只要具有同名的成员变量也认为具有该属性,如前面提到的 public $title 。

canGetProperty() 测试一个属性是否可读,参数 $checkVars 的意义同上。只要定义了getter,属性即可读。 同时,如果 $checkVars 为 true 。那么只要类定义了成员变量,不管是public, private 还是 protected, 都认为是可读。

canSetProperty() はプロパティが書き込み可能かどうかをテストします。パラメーター $checkVars の意味は上記と同じです。 setter が定義されていれば、プロパティを書き込むことができます。 同時に、 $checkVars は true になります。次に、クラスがメンバー変数を定義している限り、メンバー変数がパブリック、プライベート、または保護されているかどうかに関係なく、書き込み可能とみなされます。

オブジェクトとコンポーネント

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 つの重要な機能があります:

property

event

behavior

これら 3 つの機能は、クラスを変更するための重要なエントリ ポイントであるクラスの機能を強化および拡張するものであることは、ある程度理解できたと思います。行動。 したがって、コンポーネントは Yii において非常に高い地位を占めています。

コンポーネントは、より多くの機能と利便性を提供しながら、イベントとビヘイビアの 2 つの機能を追加しました。これにより、ある程度の効率を犠牲にしながらも開​​発が容易になります。 何らかのデータを表すクラスなど、開発中にイベントとビヘイビアの 2 つの機能を使用する必要がない場合。 すると、Componentからの継承はできず、Objectからの継承となります。 一般的なアプリケーション シナリオでは、ユーザーが入力したデータのセットを表す場合はオブジェクトを使用します。 そして、オブジェクトの挙動やその処理に応答するイベントを扱う必要がある場合には、コンポーネントを使用するのが間違いありません。 効率の点では、Object の方がネイティブ PHP クラスに近いため、可能な場合は Object を最初に使用する必要があります。

関連する推奨事項:

Yii2.0 フレームワークの紹介と実践的なプロジェクト開発ビデオチュートリアル

Yii2 中国語マニュアル

独自の PHP フレームワークをゼロから構築する

以上がPHP の Yii フレームワークのプロパティの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。