PHP のマジック メソッドは、オブジェクトのパブリック インターフェイスを難読化するように見えるため、私は通常、これらのメソッドから離れようとしました。そうは言っても、少なくとも私が読んだコードでは、それらはますます使用されているようです。これらの 3 つの魔法のメソッドを使用するための一般的なパターンはありますか?
6 に答える
__call()
プラグイン可能なインターフェイスを介してクラスに追加の機能を追加するなど、動作を実装するために使用されるのを見てきました。
次のような擬似コード:
$method = function($self) {};
$events->register('object.method', $method);
$entity->method(); // $method($this);
また、ORM など、ほぼ同様の関数を簡単に記述できます。例えば:
$entity->setName('foo'); // set column name to 'foo'
__get()/__set()
私は主に、プライベート変数へのアクセスをラップするために使用されるのを見てきました。
ORM は、頭に浮かぶ最良の例です。
$entity->name = 'foo'; // set column name to 'foo'
主な理由は、入力する必要がないことです。たとえば、ORM レコードに使用して、暗黙的なセッター/ゲッターとして機能させることができます。
使用__call()
:
$user = new User();
$user->setName("Foo Bar");
$user->setAge(42);
$user->save();
使用__set()
:
$user->name = "Foo Bar";
$user->age = 42;
これは単純な配列にマップされます:
array(
"name" => "Foo Bar",
"age" => 42
)
このような配列をデータベースに書き込む方が、必要なすべての情報を収集するために多くの手動呼び出しを行うよりもはるかに簡単です。__set()
また__get()
、パブリック メンバーに対して別の利点があります。データを検証/フォーマットできます。
それはあなたがこのようなことをすることを可能にします:
class myclass {
private $propertybag;
public function __get($name) {
if(isset($this->propertybag[$name]) {return $this->propertybag[$name];}
throw new Exception("Unknown property " . (string) $name);
}
}
$propertybag
次に、一連のプロパティ全体を1つずつ設定するのではなく、SQLクエリから1行で入力できます。
また、読み取り専用の特定のプロパティを設定できます(つまり、を介して変更することはできません__set()
)。たとえば、IDフィールドに役立つかもしれません。
__get()
また、とにコードを入れることが__set()
できるので、単一の変数を取得または設定するよりも複雑なことを行うことができます。たとえば、storeID
フィールドがある場合は、プロパティを指定することもできstoreName
ます。相互参照ルックアップを介してこれを実装できる__get()
ため、名前を実際にクラスに格納する必要がない場合があります。そしてもちろんstoreName
、で実装したくないでしょう__get()
。
そこにはたくさんの可能性があります。
もちろん、魔法の方法を使用することにはいくつかの欠点があります。私にとって最大の問題は、IDEのオートコンプリート機能が失われることです。これはあなたにとって重要かもしれないし、そうでないかもしれません。
一般的なパターンの 1 つは、クライアント用に単一のハンドルを持ち、命名規則または構成に基づいて、カプセル化されたオブジェクトまたはシングルトンへの呼び出しをプロキシすることです。
class db
{
static private $instance = null;
static public function getInstance()
{
if( self::$instance == NULL )
self::$instance = new db;
return self::$instance;
}
function fetch()
{
echo "I'm fetching\n";
}
}
class dataHandler
{
function __call($name, $argv)
{
if( substr($name, 0, 4) == 'data' )
{
$fn = substr($name, 4);
db::getInstance()->$fn($argv);
}
}
}
$dh = new dataHandler;
$dh->datafetch('foo', 'bar');
同じ原則を使用して、ドライバーを変更することなく、同じ機能の異なるバックエンドを駆動できます。
魔法のメソッドを使用すると、メンバーの定義、データの入力、取得などの反復的なタスクに関して多くのコーディングを節約できるため、退屈で長い作業を行う代わりに、前述の 3 つのメソッドを使用してコーディング時間を短縮できます。すべてのこと。必要に応じて、ネット上のさまざまなチュートリアルで見つけることができるいくつかの例を提供できます。
それが一般的なコンセンサスかどうかはわかりませんが、通常は適用する必要があります-適切な場所で使用してください. 反復的なタスク (メンバーの定義、メンバーの入力、メンバーの取得、わずかに異なる X 関数の呼び出し) を行う必要がある場合は、魔法のメソッドが役立つ場合があります。
魔法のプロパティ/メソッドが文書化されている限り、いつでも好きなときに; ORM を開発する場合など、非常に抽象的なコード層を扱う場合を除き、文書化されていない魔法は避けるべきです。
抽象層で受け入れられる
/**
* DB backed model base class.
*/
class Model {
protected $attributes = [];
function __get($name) {
return @$this->attributes[$name];
}
}
文書化されている場合は許容されます
/**
* User model backed by DB tables.
* @property-read string $first_name
* @property-read string $last_name
*/
class UserModel extends Model {
}
怠惰で容認できない (ORM を使用する場合は一般的)
/**
* This class is magical and awesome and I am a lazy shithead!
*/
class UserModel extends WhoCaresWhenEverythingIsMagical {
}