在框架開發,模組化開發等場合,我們可能有一種需求,那就是在PHP運行時動態實例化物件。
什麼是動態實例化物件呢?我們先來看PHP有一種變數函數(可變函數)的概念,例如以下程式碼:
function foo() { echo 'This is the foo function'; } $bar = 'foo'; $bar();
執行上述程式碼將會輸出「This is the foo function」。具體請參考PHP手冊:可變函數。當然,如果需要動態呼叫的話,那麼就使用call_user_func或call_user_func_array函數。這兩個函數的用法不是本文的重點,不懂的同學請查閱其它資料。回到本文的話題:什麼是動態實例化物件?本人認為動態實例化對象,也就是:需要實例化的對像是在程式運行時(run-time)動態決定(由變數決定)需要實例化什麼樣的對象,而不是直接寫死在程式碼裡。
透過上述例子我們已經知道如何在運行時動態調用一個函數了,在現在面向對向如此流行的今天,在一些程式碼中,我們需要去動態去實例化一個類,該怎麼做呢?
情況一:類別的建構子沒有參數或參數的數量是確定的
如果類別的建構子沒有參數或我們要實例化的類別根本沒有建構函數,似乎簡單一點,可以照上面的例子改一個嘛,嗯,照葫蘆畫瓢,誰不會:
程式碼範例:(建構子沒有參數)
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
很理想嘛。
情況二:類別的建構函數的參數個數不確定
這種情況就要麻煩很多了,但是如果要寫得比較通用的話,就不得不考慮這種情況了。例如,我們有以下兩個類別
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; } }
我們想要一個通用的方式來實例化這兩個類別。我們注意到FOO類別是沒有寫建構子的,或是可以認為FOO類別的建構子的參數個數為零;而BAR類別的建構子卻有參數。還好,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,似乎可以了,那麼就整理一下吧,來個通用函數,我們想這麼設計,此函數的第一個函數是要實例化的類別名,從第二個參數開始就是要實例化類別的建構子的參數,有幾個就寫幾個上去,沒有就不寫。要實作參數個數可變的函數,我們有兩種方法:
第一種是類似:
function foo($arg1, $arg2 = 123, $arg3 = 'test', $arg4 = null, ....... ) { //some code; }
的辦法,這個方法有兩個缺點,第一個是你如果需要傳100個參數就寫100個參數嗎?第二個是你還要在程式裡判斷哪個參數是不是null,或是其它預設值。 (題外話:這種寫法的參數預設值必須放在最後,你不能將沒有預設值的參數插在有預設值的中間或前面,否則你呼叫的時候也必須明確地寫上有預設值參數的值)
另一種實作參數數量可變的方法是在函數裡用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
短短四行程式碼,效果相當完美啊。那麼,如果應用到類別裡面,我們可以利用這個思想,直接寫成魔術方法,可以讓我們的類別更酷哦!
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
咔,##
function foo($a, $b) { echo '$a=', $a, '<br />'; echo '$b=', $b; } call_user_func_array('foo', array(1, 'string')); //本例输出结果: //$a=1 //$b=string############咔咔,酷吧。 ###
接下来讨论一下不使用反射类的情况。例如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中文網其他相關文章!

php把负数转为正整数的方法:1、使用abs()函数将负数转为正数,使用intval()函数对正数取整,转为正整数,语法“intval(abs($number))”;2、利用“~”位运算符将负数取反加一,语法“~$number + 1”。

实现方法:1、使用“sleep(延迟秒数)”语句,可延迟执行函数若干秒;2、使用“time_nanosleep(延迟秒数,延迟纳秒数)”语句,可延迟执行函数若干秒和纳秒;3、使用“time_sleep_until(time()+7)”语句。

php除以100保留两位小数的方法:1、利用“/”运算符进行除法运算,语法“数值 / 100”;2、使用“number_format(除法结果, 2)”或“sprintf("%.2f",除法结果)”语句进行四舍五入的处理值,并保留两位小数。

判断方法:1、使用“strtotime("年-月-日")”语句将给定的年月日转换为时间戳格式;2、用“date("z",时间戳)+1”语句计算指定时间戳是一年的第几天。date()返回的天数是从0开始计算的,因此真实天数需要在此基础上加1。

php判断有没有小数点的方法:1、使用“strpos(数字字符串,'.')”语法,如果返回小数点在字符串中第一次出现的位置,则有小数点;2、使用“strrpos(数字字符串,'.')”语句,如果返回小数点在字符串中最后一次出现的位置,则有。

方法:1、用“str_replace(" ","其他字符",$str)”语句,可将nbsp符替换为其他字符;2、用“preg_replace("/(\s|\ \;||\xc2\xa0)/","其他字符",$str)”语句。

在PHP中,可以利用implode()函数的第一个参数来设置没有分隔符,该函数的第一个参数用于规定数组元素之间放置的内容,默认是空字符串,也可将第一个参数设置为空,语法为“implode(数组)”或者“implode("",数组)”。

php字符串有下标。在PHP中,下标不仅可以应用于数组和对象,还可应用于字符串,利用字符串的下标和中括号“[]”可以访问指定索引位置的字符,并对该字符进行读写,语法“字符串名[下标值]”;字符串的下标值(索引值)只能是整数类型,起始值为0。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

Dreamweaver CS6
視覺化網頁開發工具

禪工作室 13.0.1
強大的PHP整合開發環境

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

Atom編輯器mac版下載
最受歡迎的的開源編輯器