これに対する代替アプローチは、メタプログラミングの非常に基本的な形式です。アイデアは、手動でメソッドを呼び出すよりも高いレベルに進み、コードにそれを行わせるというものです。
(メソッド定義はすべての一部であると想定しますPost
)
public function getX($model = null) {
if ($model) return $model->getX();
else return self::DEFAULT_X;
}
// usage
$postModel->getX($pictureModel);
ここで起こっていることはgetX
、Post
モデル内のこの単一のインスタンスで、別のクラスの名前を渡し、そのインスタンスで `getX'メソッドを実行していることです(存在し、呼び出し可能である場合)。
これは他の方法で拡張できます。たとえば、メソッドがとにかくそれを行うことができるのに、インスタンスを渡したくない場合があります。
public function getX($model_name = null) {
if ($model_name && $class_exists($model_name) && is_callable(array($model_name, 'getX')) {
$model = new $model_name;
return $model->getX();
} else {
return self::DEFAULT_X;
}
}
// usage
$postModel->getX('Picture');
この場合、モデルを文字列として渡すと、メソッドが残りを実行します。これにより、必要なものをすばやく取得できますが、常に新しいインスタンスを操作したくない(またはできない)場合があるため、この「便利な」とのトレードオフが少しあります。仕方。
ただし、ゲッターごとに何度も何度も繰り返す必要があるため、それでも問題を完全に解決することはできません。代わりに、次のようなことを試すことができます。
public function __call($method, $args) {
$class = $args[0];
if (class_exists($class) && is_callable(array($class, $method))) {
$model = new $class;
return $model->$method();
}
}
// usage
$postModel->getX('Picture');
$postModel->getY('Quote');
$postModel->getZ('Picture');
モデルに存在しない関数を呼び出すとPost
、そのマジックメソッドが呼び出され、引数として指定したモデル名の新しいインスタンスが起動され、getWhatever
メソッドが存在する場合はそのメソッドが呼び出されます。 。
他のクラスのメソッドをオーバーライドする場合を除いて、でこれらのゲッターを定義してはならないPost
ことに注意することが重要です。
ただし、これによって常に新しいインスタンスが作成されるという問題がまだあります。これを修正するには、依存性注入を少し使用できます。つまり、Post
クラスに将来使用するクラスの他のインスタンスのリストを含めることができるので、それらを自由に追加および削除できます。
これは私が実際の解決策と考えるものであり、他の例はうまくいけば私がここに到達した方法を示しています(もちろん、物事を明確にするために編集します)。
public $models = array();
public function addModel($instance) {
$this->models[get_class($instance)] = $instance;
}
public function __call($method, $args) {
$class = $args[0];
if (array_key_exists($class, $this->models)) {
$model = $this->models[$class];
if (is_callable(array($model, $method)) {
return $model->$method();
}
}
}
// usage
$this->addModel($pictureModel);
$this->addModel($quoteModel);
$this->getX('Picture');
$this->getY('Quote');
ここでは、モデルの既存のインスタンスをクラスに渡しますPost
。クラスは、クラスの名前でキー設定された配列にモデルを格納します。次に、最後の例で説明したようにクラスを使用すると、新しいインスタンスを作成する代わりに、すでに保存されているインスタンスが使用されます。Post
これの利点は、モデルに反映させたいことをインスタンスに対して実行できることです。
これは、プラグインする必要のある新しいモデルを好きなだけ追加できることを意味します。必要なのは、モデルにPost
を注入しaddModel
、それらのモデルにゲッターを実装することだけです。
それらはすべて、ある時点でどのモデルを呼び出すかをクラスに指示する必要があります。依存モデルの配列があるので、すべてを取得する方法を追加してみませんか?
public function __call($method, $args) {
$class = $args[0];
if (array_key_exists($class, $this->models)) {
$model = $this->models[$class];
if (is_callable(array($model, $method)) {
return $model->$method();
}
} elseif ($class === 'all') {
// return an array containing the results of each method call on each model
return array_map(function($model) use ($method) {
if (is_callable(array($model, $method) return $model->$method();
}, $this->models);
}
}
// usage
$postModel->getX('all');
getX
これを使用すると、で追加した各モデルの各メソッドの戻り値を含む配列を取得できますaddModel
。面倒なロジックを繰り返すことなく、これらすべてを実行する非常に強力な関数とクラスを作成できます。
これらの例はテストされていないことを言及する必要がありますが、少なくとも、あなたができることの概念が明確になっていることを願っています。
注:プロパティへのアクセスに使用されるメソッドにも__GET
同じ
ことが適用できます。__SET
また、ライブラリがすでにこれらの魔法のメソッドを使用しているというわずかなリスクがあるかもしれないことも言う価値があります。その場合、コードをもう少しインテリジェントにする必要があります。