在所有的編程語言中涩笤,方法或者函數(shù)贸桶,都可以傳遞一些參數(shù)進(jìn)來進(jìn)行業(yè)務(wù)邏輯的處理或者計(jì)算。這沒什么可說的儒拂,但是在PHP中寸潦,方法的參數(shù)還有許多非常有意思的能力,下面我們就來說說這方面的內(nèi)容侣灶。
引用參數(shù)
涉及到值傳遞和引用傳遞的問題甸祭。在正常情況下,我們使用值傳遞的時(shí)候褥影,變量是進(jìn)行了拷貝池户,方法內(nèi)外的變量不會(huì)共享內(nèi)存。也就是說凡怎,在方法體中修改了變量的值校焦,方法外部的變量不會(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ù)房匆。如果沒有加這個(gè)標(biāo)識(shí)耸成,則所有的基本類型參數(shù)都會(huì)以值的方式進(jìn)行傳遞。為什么要強(qiáng)調(diào)基本類型呢浴鸿?下面我們用類當(dāng)參數(shù)來測(cè)試一下:
class A
{
public $a = 1;
}
function testA($obj)
{
$obj->a++;
}
$o = new A();
testA($o);
echo $o->a; // 2
在這個(gè)例子中井氢,我們并沒有使用&標(biāo)識(shí)來表明參數(shù)$obj是引用類型的,但如果傳遞的參數(shù)是對(duì)象的話岳链,那么它默認(rèn)就是進(jìn)行的引用傳遞花竞。如果想讓對(duì)象也是值傳遞呢?抱歉掸哑,在方法參數(shù)中是沒辦法實(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)于值和引用的問題,可以參考設(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ù)開發(fā)中,很有可能一個(gè)不小心就會(huì)漏寫參數(shù)拐云,這時(shí)候testArgsA就會(huì)返回錯(cuò)誤了。當(dāng)然近她,這種粗心類的錯(cuò)誤是我們應(yīng)該盡量避免的叉瘩。
當(dāng)指定默認(rèn)值的時(shí)候,我們應(yīng)該根據(jù)參數(shù)的類型進(jìn)行指定粘捎,比如字符串就指定為''薇缅,數(shù)字就指定為數(shù)字類型。當(dāng)不確定參數(shù)是什么類型時(shí)攒磨,建議使用NULL做為默認(rèn)參數(shù)泳桦。
function testArgsD($a = NULL)
{
if ($a) {
echo $a;
}
}
testArgsD(1);
testArgsD('a');
類型聲明
類型聲明是在PHP5之后添加的功能,就像java一樣娩缰,參數(shù)前面加上參數(shù)的類型灸撰,比如:
function testAssignA(int $a = 0)
{
echo $a;
}
testAssignA(1);
testAssignA("a"); // error
如果參數(shù)的類型不對(duì),直接就會(huì)報(bào)錯(cuò)拼坎。在PHP7以前浮毯,只支持類、數(shù)組和匿名方法的類型聲明泰鸡。在PHP7之后债蓝,支持所有的普通類型,但是這里要注意的是盛龄,只支持普通類型的固定寫法饰迹。
- Class/interface name
- self
- array
- callable
- bool
- float
- int
- string
固定寫法是什么意思呢?
function testAssignB(integer $a = 0) // error
{
echo $a;
}
也就是說余舶,int只能寫int啊鸭,不能使用integer,bool也不能使用boolean欧芽。只能是上面列出的類型關(guān)鍵字莉掂。
類型聲明的好處是什么呢?其實(shí)就是Java這種靜態(tài)語言和PHP這種動(dòng)態(tài)語言之間的差別千扔。動(dòng)態(tài)類型語言的好處就是變量靈活憎妙,不用指定類型库正,方便快速開發(fā)迭代。但問題也在于靈活厘唾,為了靈活褥符,動(dòng)態(tài)語言往往會(huì)在比較或者計(jì)算時(shí)對(duì)變量進(jìn)行自動(dòng)類型轉(zhuǎn)換。如果你對(duì)變量類型轉(zhuǎn)換的理解不清晰的話抚垃,很容易就會(huì)出現(xiàn)各種類型的BUG喷楣。同時(shí),靜態(tài)類型的語言一般都會(huì)有編譯打包鹤树,而動(dòng)態(tài)類型則是在執(zhí)行時(shí)確定變量類型铣焊,所以很少會(huì)進(jìn)行編譯打包,相對(duì)來說運(yùn)行效率也就不如Java之類的編譯后語言了罕伯。
關(guān)于PHP的類型轉(zhuǎn)換問題曲伊,可以參考此前的文章:
PHP中的強(qiáng)制類型轉(zhuǎn)換
Tips一個(gè)小技巧,如果聲明了參數(shù)類型追他,是不能傳遞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è)方法來獲取所有的參數(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中。不過PHP默認(rèn)已經(jīng)幫我們解決了這個(gè)問題买羞,如果...參數(shù)后面還有參數(shù)的話袁勺,會(huì)直接報(bào)錯(cuò)。
利用這個(gè)操作符畜普,我們還可以很方便的解包一些數(shù)組或可迭代的對(duì)象給方法參數(shù)期丰,例如:
function testMultiArgsC($a, $b){
echo $a, $b;
}
testMultiArgsC(...[1, 2]);
是不是很有意思,那么我們利用這個(gè)特性來合并一個(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(...array2)的操作會(huì)報(bào)錯(cuò)埠通。
參考文檔:
https://www.php.net/manual/zh/functions.arguments.php
https://www.php.net/manual/zh/functions.arguments.php#121579
https://www.php.net/manual/zh/functions.arguments.php#120580
===========
各自媒體平臺(tái)均可搜索【硬核項(xiàng)目經(jīng)理】