フレームワーク開発やモジュール開発などでは、PHP の実行中にオブジェクトを動的にインスタンス化する必要がある場合があります。
動的にインスタンス化されたオブジェクトとは何ですか?まず、PHP の変数関数 (変数関数) の概念を見てみましょう。 たとえば、次のコード:
function foo() { echo 'This is the foo function'; } $bar = 'foo'; $bar();
上記のコードを実行すると、「これは foo 関数です」と出力されます。詳細については、PHP マニュアルの「変数関数」を参照してください。もちろん、動的に呼び出す必要がある場合は、call_user_func 関数または call_user_func_array 関数を使用します。これら 2 つの関数の使用法はこの記事の焦点ではありません。理解できない場合は、他の情報を確認してください。この記事の主題に戻ります: 動的にインスタンス化されるオブジェクトとは何ですか?オブジェクトの動的インスタンス化とは、インスタンス化する必要があるオブジェクトが、コード内に直接ハードコーディングされるのではなく、プログラムの実行時に動的に決定される (変数によって決定される) ことを意味すると私は考えています。
上記の例を通じて、オブジェクト指向が非常に人気のある今日、クラスを動的にインスタンス化する必要があることをすでに理解しています。
状況 1: クラスのコンストラクターにパラメーターがないか、パラメーターの数が決まっています
クラスのコンストラクターにパラメーターがない場合、またはインスタンス化したいクラスにコンストラクターがまったくない場合、より簡単な場合は、上記に従うことができます 例を変更するだけで、同じ例に従うことができます:
コード例: (コンストラクターにはパラメーターがありません)
class FOO { private $a, $b; public function construct() { $this->a = 1; $this->b = 2; } public function test() { echo 'This is the method test of class FOO<br />'; echo '$this->a=', $this->a, ', $this->b=', $this->b; } } $bar = 'FOO'; $foo = new $bar(); $foo->test();
実行すると、次の出力が表示されます:
This is the method test of class FOO $this->a=1, $this->b=2
そうですね、パラメーターを渡す必要があります。その場合は、これを実行してください:
class FOO { private $a, $b; public function construct($a, $b) { $this->a = $a; $this->b = $b; } public function test() { echo 'This is the method test of class FOO<br />'; echo '$this->a=', $this->a, ', $this->b=', $this->b; } } $bar = 'FOO'; $foo = new $bar('test', 5); $foo->test();
同様の結果を取得することもできます:
This is the method test of class FOO $this->a=test, $this->b=5
これは理想的です。
状況 2: クラス構築関数パラメータの数が不確実です
この状況はさらに面倒になりますが、より汎用的に書きたい場合は、この状況を考慮する必要があります。たとえば、次の 2 つのクラス
class FOO { public function test() { echo 'This is the method test of class FOO'; } } class BAR { private $a, $b; public function construct($a, $b) { $this->a = $a; $this->b = $b; } public function test() { echo 'This is the method test of class BAR<br />'; echo '$this->a=', $this->a, ', $this->b=', $this->b; } }
があり、これら 2 つのクラスをインスタンス化する共通の方法が必要です。 FOO クラスにはコンストラクターがないか、BAR クラスのコンストラクターにはパラメーターがある一方で、FOO クラスのコンストラクターのパラメーターの数はゼロであると考えることができます。幸いなことに、PHP5 は十分強力であり、リフレクションの概念が導入されています。詳細については、PHP マニュアル「リフレクション」を参照してください。ただし、マニュアルには参照するものはありません :)。幸いなことに、名前付けはクラス名とメソッド名からすでに大まかに理解できるので、多くの言葉は必要ありません。
それでは、PHP5 のリフレクションを使用してこの問題を始めましょう:
(まだ PHP4 を使用している学生は、立ち去らないでください。リフレクションのない PHP バージョンを使用している場合、またはリフレクションの目的で使用したくない場合は、互換性、アップグレードするかどうかは関係ありません、とにかくリフレクションを使用したくないのですが、以下に解決策があります)
$class = new ReflectionClass('FOO'); $foo = $class->newInstance(); //或者是$foo = $class->newInstanceArgs(); $foo->test();
何か見えましたか?次:
$class = new ReflectionClass('BAR'); $bar = $class->newInstanceArgs(array(55, 65)); $bar->test();
OK、それは良さそうなので、それを整理して、次のように設計したいと思います。この関数の最初の関数は、インスタンス化されるクラスの名前です。 2 番目のパラメーター。クラスのコンストラクターのパラメーターをインスタンス化するには、存在するだけ記述します。そうでない場合は、記述しないでください。変数の数を指定して関数を実装するには、次の 2 つの方法があります:
1 つ目は、次のようなメソッドです:
function foo($arg1, $arg2 = 123, $arg3 = 'test', $arg4 = null, ....... ) { //some code; }
この方法には 2 つの欠点があります。パラメーターに 100 個? 2 つ目は、プログラム内のどのパラメータが null またはその他のデフォルト値であるかを判断する必要があることです。 (余談: この書き方ではパラメータのデフォルト値は最後に置く必要があります。デフォルト値のないパラメータをデフォルト値のあるパラメータの途中や前に挿入することはできません。それ以外の場合は、明示的にパラメータを挿入する必要もあります。 value)
パラメーターの数を可変にする別の方法は、PHP の 組み込み関数 func_get_args (ここをクリックしてマニュアルを参照) を使用して、渡されるパラメーターを取得することです。関数内の関数。同様の関数には func_get_num と func_get_arg があります。面倒なのでマニュアルを見つけて読んでください。
したがって、関数パラメータの想像上の配置に基づいて、コードは次のようになります:
function newInstance() { $arguments = func_get_args(); $className = array_shift($arguments); $class = new ReflectionClass($className); return $class->newInstanceArgs($arguments); }
OK、効果を見てみましょう:
$foo = newInstance('FOO'); $foo->test(); //输出结果: //This is the method test of class FOO $bar = newInstance('BAR', 3, 5); $bar->test(); //输出结果: //This is the method test of class BAR //$this->a=3, $this->b=5
わずか 4 行のコードで、効果は非常に完璧です。次に、このアイデアをクラスに適用すると、マジック メソッド として直接記述することができ、クラスをさらにクールにすることができます。
class INSTANCE { function call($className, $arguments) { $class = new ReflectionClass($className); return $class->newInstanceArgs($arguments); } } $inst = new INSTANCE(); $foo = $inst->foo(); $foo->test(); //输出结果: //This is the method test of class FOO $bar = $inst->bar('arg1', 'arg2'); $bar->test(); //输出结果: //This is the method test of class BAR //$this->a=3, $this->b=5
カカ、気持ちいいよ。
次に、リフレクションクラスを使用せずに状況を説明します。たとえば、PHP4 にはリフレクションがなく、一部の古いプロジェクトは PHP4 で実行されます。または、プロジェクトの未知の環境との互換性を確保したい場合は、パラメータを動的に転送する方法を考慮しましょう。 PHP には動的パラメータ転送用の関数が 1 つだけあります: call_user_func_array (マニュアルを表示するにはここをクリックしてください)。これは、関数を動的に呼び出す関数であり、その機能は、関数のパラメータを配列の形式で呼び出す関数に渡すことです。さて、私自身も混乱していたので、例を直接見てみましょう:
function foo($a, $b) { echo '$a=', $a, '<br />'; echo '$b=', $b; } call_user_func_array('foo', array(1, 'string')); //本例输出结果: //$a=1 //$b=string
那么,要实现用这种方法来动态实例化对象并传参,呃……,只有曲线救国了,我们得先写一个函数,让这个函数来实例化对象,而这个函数的参数就原原本本地传给要实例化对象的类的构造函数就好了。打住!那这个函数得有几个参数啊?怎么实现传递不同个数的参数呢?嘿嘿,我一声冷笑,你忘了PHP里提供一个创建匿名函数的函数吗?(又开始绕起来了……)create_function(手册在此),照着手册里面的例子直接画就可以了,我也懒得打字了,直接看下面的代码,注释我写清楚点大家都明白了:
function newInst() { //取得所有参数 $arguments = func_get_args(); //弹出第一个参数,这是类名,剩下的都是要传给实例化类的构造函数的参数了 $className = array_shift($arguments); //给所有的参数键值加个前缀 $keys = array_keys($arguments); array_walk($keys, create_function('&$value, $key, $prefix', '$value = $prefix . $value;'), '$arg_'); //动态构造实例化类的函数,主要是动态构造参数的个数 $paramStr = implode(', ',$keys); $newClass=create_function($paramStr, "return new {$className}({$paramStr});"); //实例化对象并返回 return call_user_func_array($newClass, $arguments); }
好了,至于效果是什么,就麻烦各位看官自己动动手,运行一下看看,是不是自己期望的结果。
以上がPHP フレームワークにおける動的インスタンス化オブジェクトの詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。