フレームワーク開発やモジュール開発などでは、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上面的。或者是要保证项目对未知环境的兼容性,Whatever,来关心一下怎么动态传参吧。PHP中动态传参的函数只有一个: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); }
好了,至于效果是什么,就麻烦各位看官自己动动手,运行一下看看,是不是自己期望的结果。
如果改写成类里面的魔术方法,哼哼,威力嘛,你懂的!然后呢,我还是懒了,如果要写成魔术方法的话,相信这么easy的事情你很轻松就办到了。就当一个作业吧。另,本文的代码都是本人运行过的,但是,写文章的时候没有使用复制/粘贴功能,所以,你最好是也不要复制粘贴。如果从本文中的代码copy下来运行出错的话,还烦请各位自己debug一下,编程不就是要自己写么。
本来这个话题到这里就应该可以结束了,但是想到我在想到这个办法之前用的方法(好绕……),本着重在交流的态度,一起放出来。我例两个关键函数吧:extract和eval。只是我个人觉得用eval函数比较山寨,能不用最好不用。于是又想出了上面的办法,哈哈,编程最重要的是思想,不是吗?好,又是一道作业题了,大家可以试试用这两个函数(当然也会用到别的函数)来实现带不定数量的参数动态实例化对象的函数。
以上がオブジェクトを動的にインスタンス化し、コンストラクターにパラメータを渡すPHPのケース分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。