テキスト/コンパイル: Zhu Xianzhong
1. はじめ
に幸いなことに、オブジェクト オーバーロード テクノロジは PHP 5.0 で導入されました。この記事では、メソッド __call()、__set()、および __get() をオーバーロードする可能性について検討します。オーバーロード理論について簡単に説明した後、2 つの例を通して本題に進みます。最初の例は永続ストレージ クラスを実装することであり、2 番目の例は動的ゲッター/セッターを実装する方法を見つけることです。
2. オブジェクトのオーバーロードとは何ですか?
PHP でオブジェクトのオーバーロードについて話すときは、次の 2 つのタイプを区別する必要があります。
· メソッドのオーバーロード
· 属性のオーバーロード
メソッドのオーバーロードの場合は、未定義のメソッドへの汎用呼び出しを実装するマジック メソッド __call() を定義する必要があります。対応するクラスで。この一般的なメソッドは、クラス内の未定義のメソッドにアクセスする場合にのみ呼び出されます。メソッドのオーバーロードを行わない場合、次の例では PHP に致命的なエラー メッセージが表示されます。「未定義メソッド ThisWillFail::bar() in/some/directory/example.php 行 9 を呼び出し、プログラムの実行を中止します:
< ?php」
クラス ThisWillFail {
パブリック関数 foo() {
「Hello World!」を返します。
}
}
$class = 新しい ThisWillFail;
$class->bar();
?>
メソッドのオーバーロードを利用すると、コードはこの呼び出しをキャッチして適切に処理できます。
プロパティのオーバーロードはメソッドのオーバーロードに似ています。この場合、クラスは、クラス内で明示的に定義されていないクラスのプロパティに読み取り/書き込み操作をリダイレクトします (プロキシとも呼ばれます)。ここでの特殊なメソッドは __set() と __get() です。エラー報告レベルに応じて、PHP トランスレータは通常、未定義のプロパティにアクセスしたときに通知を発行するか、変数を延期して潜在的に定義します。属性のオーバーロードを使用する場合、トランスレーターは、未定義の属性を設定するときに __set() を呼び出し、未定義の属性値にアクセスするときに __get() を呼び出すことができます。
要約すると、オーバーロード技術を使用すると、PHP などの動的言語を使用する場合のソフトウェア開発時間を大幅に短縮できます。
ここで理論を紹介し、以下で具体的なコーディングを分析します。
3. 永続ストレージ クラスの例
次のコードは、属性オーバーロード技術を使用して、50 行未満の PHP コードで上記の永続ストレージ クラスを実装します。永続的という用語は、クラスがデータ構造から要素を記述でき、基礎となるストレージ システムとの同期を維持できることを意味します。コーディング用語では、外部コードはクラスを使用してデータベース テーブルから行を選択できます。このようにして、プログラムの実行中に、クラスの属性に直接アクセスして、行内の要素を操作 (読み取り/フェッチ) できます。スクリプトの最後で、PHP は更新された行データをデータベースに送り返します。
次のコードを注意深く検討すると、属性のオーバーロードとは何かを理解するのに役立ちます。
<?php
//PEARの<a href=" http://pear.php.net/package/DB/ "> DBパッケージ</a>をロードします
require_once "DB.php";
クラス永続化 {
プライベート $data = array();
プライベート $table = "ユーザー";
パブリック関数 __construct($user) {
$this->dbh = DB::Connect("mysql://user:password@localhost/database");
$query = "ID、名前、メールアドレス、国を FROM " から選択します。
$this->table . " WHERE name = ?";
$this->data = $this->dbh->getRow($query, array($user),
DB_FETCHMODE_ASSOC);
}
パブリック関数 __get($member) {
if (isset($this->data[$member])) {
$this->data[$member] を返します。
}
}
パブリック関数 __set($member, $value) {
//データセットの ID は読み取り専用です if ($member == "id") {
戻る;
}
if (isset($this->data[$member])) {
$this->data[$member] = $value;
}
}
パブリック関数 __destruct() {
$query = "UPDATE " . $this->table . SET name = ?,
電子メール = ?、国 = ? WHERE ID = ?";
$this->dbh->query($query, $this->name, $this->email,
$this->country, $this->id);
}
}
$class = new Persistable("マーティン ジャンセン");
$class->name = "ジョン・ドゥ";
$class->country = "米国";
$class->email = " [email protected] ";
?>
最初に遭遇する可能性のある問題は、PHP 5 で導入された新しいコンストラクター メソッドである __construct() です。 PHP 4 の時代、コンストラクターは常にクラス名と一致していました。 PHP 5 ではこれは当てはまりません。コンストラクター メソッドについて詳しく知る必要はありませんが、呼び出すとクラスのインスタンスが作成されることと、ここでパラメーターが使用されていることに注意してください。データベースはこのパラメーターに基づいて実行されます。このコンストラクターは、クエリ結果をクラス属性 $data に割り当てます。
次に、プログラムは 2 つの特別なメソッド __get() と __set() を定義します。 __get() は未定義の属性値を読み取るために使用され、__set() は未定義の属性値を変更するために使用されます。
これは、未定義のプロパティが永続ストレージ クラスから読み書きされるたびに、これらの特殊なメソッドが、クラスのプロパティを直接変更するのではなく、プロパティ配列変数 $data 内の情報を管理する責任を負うことを意味します (変数 $data を思い出してください)データベースの行が含まれています!)。
クラスの最後のメソッドは、__construct() の逆、デストラクター __destruct() です。 PHP は、通常、PHP スクリプトの実行の終わり近くにある「スクリプト シャットダウン フェーズ」中にデストラクターを呼び出します。デストラクターは、$data 属性の情報をデータベースに書き込みます。これはまさに、前の用語の同期が意味するものです。
ここのコードでは PEAR のデータベース抽象化レイヤー パッケージが使用されていることに気づいたかもしれません。実際、他の方法でデータベースと通信することも、この記事のテーマを説明するのに役立ちます。
よく見ると、この永続ストレージ クラスの説明が比較的単純であることがわかります。この例にはデータベース テーブルのみが含まれており、LEFT JOIN やその他の複雑なデータベース操作テクニックの使用など、より複雑なデータ モデルは考慮されていません。ただし、これに拘束される必要はなく、プロパティのオーバーロードを利用して、独自の理想的なデータベース モデルを使用できます。ほんの少しのコードを記述するだけで、この永続ストレージ クラスの複雑なデータベース機能を利用できます。
また、小さな問題もあります。デストラクターでクエリが失敗した場合のエラー処理メカニズムが導入されていません。この場合、デストラクターの性質上、適切なエラー メッセージを表示することができません。これは、PHP がデストラクターを呼び出す前に HTML マークアップの構築が終了することが多いためです。
この問題を解決するには、__destruct() の名前を saveData() などに変更し、呼び出し側スクリプトのどこかでこのメソッドを手動で実行します。これはクラスの永続ストレージの概念を変えるものではなく、コードを数行追加するだけです。あるいは、デストラクターで error_log() 関数を使用して、システム全体のエラー ログ ファイルにエラー メッセージを記録することもできます。
これがプロパティのオーバーロードの仕組みです。次にメソッドのオーバーロードについて説明します。
4. メソッドのオーバーロードの例
1. 動的 Getter/Setter メソッド
次のコードは、メソッドのオーバーロードを利用してクラスを制御する「動的」getter/setter メソッドを実装しています。ソースコードに基づいて分析してみましょう:
<?php
クラス DynamicGetterSetter {
private $name = "マーティン・ジャンセン";
private $starbucks Drink = "キャラメル カプチーノ スワール";
function __call($method, $arguments) {
$prefix = strto lower(substr($method, 0, 3));
$property = strto lower(substr($method, 3));
if (empty($prefix) || empty($property)) {
戻る;
}
if ($prefix == "get" && isset($this->$property)) {
$this->$property を返します。
}
if ($prefix == "セット") {
$this->$property = $arguments[0];
}
}
}
$class = 新しいDynamicGetterSetter;
echo "名前: " . $class->getName() ";
echo "お気に入りのスターバックスのフレーバー: " . $class->getStarbucksDrink() "nn";
$class->setName("ジョン・ドゥ");
$class->setStarbucksDrink("クラシック コーヒー");
echo "名前: " . $class->getName() ";
echo "お気に入りのスターバックスのフレーバー: " . $class->getStarbucksDrink() "nn";
?>
明らかに、ここでの 2 つの属性 $name と $starbucks Drink はプライベートです。これは、これらの属性にクラスの外部からアクセスできないことを意味します。オブジェクト指向プログラミングでは、非パブリック プロパティの値にアクセスまたは変更するためにパブリックの getter/setter メソッドを実装することが非常に一般的です。これらの実装は面倒で時間と労力がかかります。
この問題は、メソッドのオーバーロードを利用することで簡単に解決できます。上記では、プロパティごとにゲッター/セッター メソッドを実装する代わりに、一般的な __call() メソッドのみを実装しています。これは、setName() や getStarbucks Drink() などの未定義のゲッター/セッター メソッドが呼び出された場合、PHP は致命的なエラーを生成して中止するのではなく、代わりにマジック __call() メソッドを実行 (または委任) することを意味します。
これらは簡単な紹介です。__call() を詳しく分析してみましょう。
2. __call() メソッドの詳細な分析
__call() の最初のパラメーターは、元の未決定のメソッド (setName など) であり、2 番目のパラメーターは、すべての元のメソッドを含む数値インデックスを持つ 1 次元配列です。 .パラメータ。 2 つのパラメーター ("Martin" と 42) を指定して未定義のメソッドを呼び出すと、次の配列が生成されます。
$class->thisMethodDoesNotExist("Martin", 42);
/__call() の 2 番目のパラメーターのガイド
配列
(
[0] =>マーティン
[1] => 42
)
メソッド __call() 内で、元のメソッドが get または set で始まる場合、コードが getter/setter メソッドを呼び出すかどうかを判断するために何らかの計算を実行する必要があります。さらに、文字列の後半部分はゲッター/セッターによって参照される属性の名前を表すため、このメソッドはメソッド名の別のコンポーネント (最初の 3 文字を除く) をさらに分析します。
メソッド名がゲッター/セッターを示している場合、メソッドは対応するプロパティ値を返すか、元のメソッドの最初のパラメーターの値を設定します。そうでない場合は、何もせず、何事もなかったかのようにプログラムの実行を続けます。
3. 目標を達成するには、
本質的に、任意の属性に対応して、コードが任意の getter/setter メソッドを動的に呼び出すことを可能にするメソッドが存在します。このアルゴリズムが存在します。これは、プログラムのプロトタイプを短期的に開発する場合に便利です。開発者は、ゲッター/セッターの実装に多くの時間を費やす代わりに、API のモデル化とアプリケーションが基本的に正しいことの確認に集中できます。 __call() メソッドを抽象クラスに組み込むと、将来の PHP プロジェクト開発でコードを再利用できる場合もあります。
4. 欠点に加えて、
利点と欠点もあります。上記のアプローチにはいくつかの欠点があります。大規模なプロジェクトでは、API 構造を追跡するために phpDocumentor などのツールを使用する場合があります。上記で紹介した動的メソッドでは、もちろん、すべてのゲッター/セッター メソッドが自動生成されたドキュメントに表示されるわけではありません。これについては、これ以上説明する必要はありません。
もう 1 つの欠点は、クラス外のコードがクラス内のすべてのプライベート プロパティにアクセスできることです。実際のゲッター/セッター メソッドを使用する場合、外部コードからアクセスできるプライベート プロパティと、クラスの外部には表示されない「実際の」プライベート プロパティを区別することができます。これは、メソッドのオーバーロードがあり、仮想ゲッターとセッターがあるためです。メソッドを使用できます。
5. 結論
この記事では、2 つの例を通して、PHP 5.0 におけるオブジェクトのオーバーロードの 2 つの状況を注意深く分析します。この記事の方法が PHP プログラミングの効率向上に役立つことを強く願っています。同時に、この方法の欠点も明確に理解していただけるはずです。