關(guān)于PHP方法參數(shù)的那一些事
前言
在所有的編程語(yǔ)言中,方法或者函數(shù),都可以傳遞一些參數(shù)進(jìn)來(lái)進(jìn)行業(yè)務(wù)邏輯的處理或者計(jì)算。這沒(méi)什么可說(shuō)的,但是在PHP中,方法的參數(shù)還有許多非常有意思的能力,下面我們就來(lái)說(shuō)說(shuō)這方面的內(nèi)容。
引用參數(shù)
涉及到值傳遞和引用傳遞的問(wèn)題。在正常情況下,我們使用值傳遞的時(shí)候,變量是進(jìn)行了拷貝,方法內(nèi)外的變量不會(huì)共享內(nèi)存。也就是說(shuō),在方法體中修改了變量的值,方法外部的變量不會(huì)產(chǎn)生變化。而引用傳遞則是傳遞的變量的內(nèi)存地值。方法內(nèi)外的變量可以看做是同一個(gè)變量,比如:
$a = 1; function test(&$arg){ $arg++; } test($a); echo $a; // 2
為參數(shù)加上&標(biāo)識(shí),就表明這個(gè)參數(shù)是引用傳遞的參數(shù)。如果沒(méi)有加這個(gè)標(biāo)識(shí),則所有的基本類(lèi)型參數(shù)都會(huì)以值的方式進(jìn)行傳遞。為什么要強(qiáng)調(diào)基本類(lèi)型呢?下面我們用類(lèi)當(dāng)參數(shù)來(lái)測(cè)試一下:
class A { public $a = 1; } function testA($obj) { $obj->a++; } $o = new A(); testA($o); echo $o->a; // 2
在這個(gè)例子中,我們并沒(méi)有使用&標(biāo)識(shí)來(lái)表明參數(shù)$obj是引用類(lèi)型的,但如果傳遞的參數(shù)是對(duì)象的話,那么它默認(rèn)就是進(jìn)行的引用傳遞。如果想讓對(duì)象也是值傳遞呢?抱歉,在方法參數(shù)中是沒(méi)辦法實(shí)現(xiàn)的,只能在方法體中使用clone方式對(duì)對(duì)象參數(shù)進(jìn)行克隆。
class A { public $a = 1; } function testA($obj) { $o = clone $obj; $o->a++; } $o = new A(); testA($o); echo $o->a; // 1
關(guān)于值和引用的問(wèn)題,可以參考設(shè)計(jì)模式中原型模式的講解:PHP設(shè)計(jì)模式之原型模式
默認(rèn)參數(shù)
參數(shù)是可以有默認(rèn)值的,這個(gè)我想大家都應(yīng)該很清楚了。但是在使用的時(shí)候也需要注意,那就是默認(rèn)參數(shù)不要放在前面,否則很容易出錯(cuò),比如:
function testArgsA($a = 1, $b){ echo $a+$b; } testArgs(); // error function testArgsB($a = 1, $b = 2){ echo $a+$b; } testArgsB(); // 3 function testArgsC($a, $b = 2){ echo $a+$b; } testArgsC(1); // 3
在復(fù)雜的函數(shù)或者緊急的業(yè)務(wù)開(kāi)發(fā)中,很有可能一個(gè)不小心就會(huì)漏寫(xiě)參數(shù),這時(shí)候testArgsA就會(huì)返回錯(cuò)誤了。當(dāng)然,這種粗心類(lèi)的錯(cuò)誤是我們應(yīng)該盡量避免的。
當(dāng)指定默認(rèn)值的時(shí)候,我們應(yīng)該根據(jù)參數(shù)的類(lèi)型進(jìn)行指定,比如字符串就指定為'',數(shù)字就指定為數(shù)字類(lèi)型。當(dāng)不確定參數(shù)是什么類(lèi)型時(shí),建議使用NULL做為默認(rèn)參數(shù)。
function testArgsD($a = NULL) { if ($a) { echo $a; } } testArgsD(1); testArgsD('a');
類(lèi)型聲明
類(lèi)型聲明是在PHP5之后添加的功能,就像java一樣,參數(shù)前面加上參數(shù)的類(lèi)型,比如:
function testAssignA(int $a = 0) { echo $a; } testAssignA(1); testAssignA("a"); // error
如果參數(shù)的類(lèi)型不對(duì),直接就會(huì)報(bào)錯(cuò)。在PHP7以前,只支持類(lèi)、數(shù)組和匿名方法的類(lèi)型聲明。在PHP7之后,支持所有的普通類(lèi)型,但是這里要注意的是,只支持普通類(lèi)型的固定寫(xiě)法。
- Class/interface name
- self
- array
- callable
- bool
- float
- int
- string
固定寫(xiě)法是什么意思呢?
function testAssignB(integer $a = 0) // error { echo $a; }
也就是說(shuō),int只能寫(xiě)int,不能使用integer,bool也不能使用boolean。只能是上面列出的類(lèi)型關(guān)鍵字。
類(lèi)型聲明的好處是什么呢?其實(shí)就是Java這種靜態(tài)語(yǔ)言和PHP這種動(dòng)態(tài)語(yǔ)言之間的差別。動(dòng)態(tài)類(lèi)型語(yǔ)言的好處就是變量靈活,不用指定類(lèi)型,方便快速開(kāi)發(fā)迭代。但問(wèn)題也在于靈活,為了靈活,動(dòng)態(tài)語(yǔ)言往往會(huì)在比較或者計(jì)算時(shí)對(duì)變量進(jìn)行自動(dòng)類(lèi)型轉(zhuǎn)換。如果你對(duì)變量類(lèi)型轉(zhuǎn)換的理解不清晰的話,很容易就會(huì)出現(xiàn)各種類(lèi)型的BUG。同時(shí),靜態(tài)類(lèi)型的語(yǔ)言一般都會(huì)有編譯打包,而動(dòng)態(tài)類(lèi)型則是在執(zhí)行時(shí)確定變量類(lèi)型,所以很少會(huì)進(jìn)行編譯打包,相對(duì)來(lái)說(shuō)運(yùn)行效率也就不如Java之類(lèi)的編譯后語(yǔ)言了。
關(guān)于PHP的類(lèi)型轉(zhuǎn)換問(wèn)題,可以參考此前的文章:PHP中的強(qiáng)制類(lèi)型轉(zhuǎn)換
Tips一個(gè)小技巧,如果聲明了參數(shù)類(lèi)型,是不能傳遞NULL值的,比如:
function testAssignC(string $a = '') { if ($a) { echo __FUNCTION__ . ':' . $a; } } testAssignC(NULL); // TypeError
這時(shí)有兩種方式可以解決,一是指定默認(rèn)值=NULL,二是使用?操作符:
function testAssignD(string $a = NULL) { if ($a == NULL) { echo 'null'; } } testAssignD(NULL); // null function testAssignE(?string $a) { if ($a == NULL) { echo 'null'; } } testAssignE(NULL); // null
可變數(shù)量參數(shù)
php中的方法可以接收可變數(shù)量的參數(shù),比如:
function testMultiArgsA($a) { var_dump(func_get_arg(2)); var_dump(func_get_args()); var_dump(func_num_args()); echo $a; } testMultiArgsA(1, 2, 3, 4);
我們只定義了一個(gè)參數(shù)$a,但是傳進(jìn)去了四個(gè)參數(shù),這時(shí)我們可以使用三個(gè)方法來(lái)獲取所有的參數(shù):
- func_get_arg(int $arg_num),獲取參數(shù)列表中的某個(gè)指定位置的參數(shù)
- func_get_args(),獲取參數(shù)列表
- func_num_args(),獲取參數(shù)數(shù)量
此外,php還提供了...操作符,用于將可變長(zhǎng)度的參數(shù)定義到一個(gè)參數(shù)變量中,如:
function testMultiArgsB($a, ...$b) { var_dump(func_get_arg(2)); var_dump(func_get_args()); var_dump(func_num_args()); echo $a; var_dump($b); // 除$a以外的 } testMultiArgsB(1, 2, 3, 4);
和參數(shù)默認(rèn)值一樣,有多個(gè)參數(shù)的情況下,...b也不要放在前面,這樣后面的參數(shù)并不會(huì)有值,所有的參數(shù)都會(huì)在b也不要放在前面,這樣后面的參數(shù)并不會(huì)有值,所有的參數(shù)都會(huì)在b中。不過(guò)PHP默認(rèn)已經(jīng)幫我們解決了這個(gè)問(wèn)題,如果...參數(shù)后面還有參數(shù)的話,會(huì)直接報(bào)錯(cuò)。
利用這個(gè)操作符,我們還可以很方便的解包一些數(shù)組或可迭代的對(duì)象給方法參數(shù),例如:
function testMultiArgsC($a, $b){ echo $a, $b; } testMultiArgsC(...[1, 2]);
是不是很有意思,那么我們利用這個(gè)特性來(lái)合并一個(gè)數(shù)組會(huì)是什么效果呢?
$array1 = [[1],[2],[3]]; $array2 = [4]; $array3 = [[5],[6],[7]]; $result = array_merge(...$array1); // Legal, of course: $result == [1,2,3]; print_r($result); $result = array_merge($array2, ...$array1); // $result == [4,1,2,3] print_r($result); $result = array_merge(...$array1, $array2); // Fatal error: Cannot use positional argument after argument unpacking. $result = array_merge(...$array1, ...$array3); // Legal! $result == [1,2,3,5,6,7] print_r($result);
和方法聲明參數(shù)時(shí)一樣,在外部使用...操作符給方法傳遞參數(shù)時(shí),也不能在...后面再有其他參數(shù),所以array_merge(...array1, array1,array2)的操作會(huì)報(bào)錯(cuò)。
測(cè)試代碼:
https://github.com/zhangyue0503/dev-blog/blob/master/php/201911/source/PHP%E6%96%B9%E6%B3%95%E5%8F%82%E6%95%B0%E7%9A%84%E9%82%A3%E7%82%B9%E4%BA%8B%E5%84%BF.php
參考文檔:
- https://www.php.net/manual/zh/functions.arguments.php
- https://www.php.net/manual/zh/functions.arguments.php#121579
總結(jié)
到此這篇關(guān)于關(guān)于PHP方法參數(shù)的文章就介紹到這了,更多相關(guān)PHP方法參數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
PHP根據(jù)樹(shù)的前序遍歷和中序遍歷構(gòu)造樹(shù)并輸出后序遍歷的方法
這篇文章主要介紹了PHP根據(jù)樹(shù)的前序遍歷和中序遍歷構(gòu)造樹(shù)并輸出后序遍歷的方法,涉及php數(shù)據(jù)結(jié)構(gòu)與算法中關(guān)于數(shù)的遍歷相關(guān)操作技巧,需要的朋友可以參考下2017-11-11完美解決令人抓狂的zend studio 7代碼提示(content Assist)速度慢的問(wèn)題
本篇文章是對(duì)解決令人抓狂的zend studio 7代碼提示(content Assist)速度慢的問(wèn)題進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06php實(shí)現(xiàn)的三個(gè)常用加密解密功能函數(shù)示例
這篇文章主要介紹了php實(shí)現(xiàn)的三個(gè)常用加密解密功能函數(shù),涉及php針對(duì)字符串的遍歷、截取、編碼轉(zhuǎn)換等相關(guān)操作技巧,需要的朋友可以參考下2017-11-11漂亮的thinkphp 跳轉(zhuǎn)頁(yè)封裝示例
今天小編就為大家分享一篇漂亮的thinkphp 跳轉(zhuǎn)頁(yè)封裝示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-10-10使用Smarty 獲取當(dāng)前日期時(shí)間和格式化日期時(shí)間的方法詳解
本篇文章是對(duì)使用Smarty獲取當(dāng)前日期時(shí)間和格式化日期時(shí)間的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06PHP構(gòu)造函數(shù)與析構(gòu)函數(shù)用法示例
這篇文章主要介紹了PHP構(gòu)造函數(shù)與析構(gòu)函數(shù)用法,簡(jiǎn)單講述php中構(gòu)造函數(shù)與析構(gòu)函數(shù)的定義與使用方法,并結(jié)合實(shí)例形式演示了構(gòu)造函數(shù)與析構(gòu)函數(shù)的執(zhí)行順序,需要的朋友可以參考下2016-09-09