PHP函數引數的傳遞

2020-07-16 10:05:10
PHP 支援兩種引數傳遞方式,分別是按值傳遞(預設)和按參照傳遞。另外,PHP 還支援預設引數和可變長度參數列。

引數傳遞方式

在呼叫函數時需要向函數傳遞引數,被傳入的引數稱作實參,而函數定義的引數為形參。PHP 中函數引數傳遞有 2 種方式:按值傳遞和通過參照傳遞。

按值傳遞

按值傳遞的引數相當於在函數內部有這個引數的備份,即使在函數內部改變引數的值,也並不會改變函數外部的值,範例如下:
<?php
function test($a){
    $a = $a + 1;
     return $a;
}
$a = 1;
echo test($a);
test(2);
echo $a;
?>
執行以上程式碼的結果為:

2 3 1

通過參照傳遞引數

如果希望允許函數修改它的引數值,就必須通過參照傳遞引數。這樣我們在函數內部是對這個引數本身進行操作。範例如下:
<?php
function test(&$a){
    $a = $a + 1;
    return $a;
}
$x = 1;
echo test($x);
echo $x;
?>
當呼叫一次 test() 函數後,$x 的值被改變,執行以上程式碼的執行結果為:

2 2

注意,以下這種情況 PHP 會報錯:
<?php
function test(&$a){
    $a = $a + 1;
    return $a;
}
test(2);  //參照傳遞的引數必須是一個變數
?>
執行以上程式碼會報錯“Fatal error:Only variables can be passed by reference”。

預設引數

PHP 支援函數預設引數,允許使用數位、字串、陣列、NULL 等作為預設引數。預設引數的值必須是常數表示式,不能是諸如變數、類成員或者函數呼叫等。

預設引數範例如下:
<?php
function test($arr=array('lily','andy','ricky'), $str='apple'){
    echo "I am $arr[1],I love $str <br/>";
}
$names = ['sily','celon','tom'];
$fruit = 'orange';
test();
test($names,$fruit);
?>
執行以上程式碼的結果為:

I am andy,I love apple
I am celon,I love orange 


為了避免出現意外情況,一般將預設引數放在非預設引數的右側。下面是一個反面教材:
<?php
function?makeyogurt($type="acidophilus", $flavour){
    return "Making a bowl of $type? flavour.n";
}
echo makeyogurt("raspberry");
?>
報錯資訊:

Warning: Missing argument 2 for makeyogurt(), called in /Library/WebServer/Documents/book/str.php on line 284 and defined in /Library/WebServer/Documents/book/str.php on line 279
Making a bowl of raspberry .

若將$type="acidophilus"放在引數的最右側,則不會報錯。

引數型別宣告

在 PHP 5 中已引入函數的引數型別宣告,如果給定的值不是一個合法的引數型別,那麼在 PHP 5 中會出現一個 Fatal error,在 PHP 7 中則會丟擲一個 TypeError exception。在 PHP 7 中增加了引數可宣告的型別種類。PHP 中函數可宣告的引數型別如表所示。

引數宣告型別
型別 說明 PHP 版本
class/interface name(類,介面) 引數必須是指定類或介面的範例 PHP 5.0.0
Array 引數為陣列型別 PHP 5.1.0
Callable 引數為有效的回撥型別 PHP 5.4.0
Bool 引數為布林型 PHP 7.0.0
Float 引數為浮點型 PHP 7.0.0
Int 引數為整型 PHP 7.0.0
String 引數為字串 PHP 7.0.0
class/interface name(類,介面) 引數必須是指定類或介面的範例 PHP 5.0.0
Array 引數為陣列型別 PHP 5.1.0

指定引數型別為 class 型別的範例如下:
<?php
class C{}
class D extends C{}      //類D繼承自類C
class E{}
functionf(C$c){
    echo?get_class($c)."n";
}
f(new C);
f(new D);
f(new E);
?>
執行以上程式的結果是:

C D
Fatal error: Uncaught TypeError: Argument 1 passed to f() must be an instance of C, instance of E given, called in /Library/WebServer/Documents/book/str.php on line 293 and defined in /Library/WebServer/Documents/book/str.php:287 Stack trace: #0 /Library/WebServer/Documents/book/str.php(293): f(Object(E)) #1 {main} thrown in /Library/WebServer/Documents/book/str.php on line 287


預設情況下,當傳遞的引數不是函數指定的引數型別時,PHP 會嘗試將所傳引數轉換成指定引數型別。例如,一個函數希望得到一個字串型別的引數,但假如給其提供的是一個整型引數,PHP 就會自動將其轉換成字串型別,或者一個函數希望得到一個整型引數,但卻給它傳遞了一個浮點型的引數。範例如下:
<?php
function test(int $a,string $b,string $c){
    echo ($a + $b);
    echo " the string is $c";
}
test(3.8,2,'hello');
?>
執行以上程式碼的列印結果為:

5 the string is hello

注意,在將浮點型轉成整型時,只取其中的整數部分。

在 PHP 7 中,可以使用 declare(strict_types=1) 設定嚴格模式,這樣只有在傳遞的引數與函數期望得到的引數型別一致時才能正確執行,否則會丟擲錯誤。只有一種情況例外,就是當函數期望得到的是一個浮點型資料而提供的是整型時,函數也能正常被呼叫。請看如下範例:
<?php
declare(strict_types=1);
function test(int $a,int $b,string $c){
    echo ($a + $b);
    echo " the string is $c";
}
test(3.8,2,'hello');
?>
此處 declare 宣告了 PHP 為嚴格模式,而傳入的引數與函數期望得到的引數型別不一致,所以會報錯,如下所示:

Fatal error: Uncaught TypeError: Argument 1 passed to test() must be of the type integer, float given, called in /Library/WebServer/Documents/book/str.php on line 285 and defined in /Library/WebServer/Documents/book/str.php:281 Stack trace: #0 /Library/WebServer/Documents/book/str.php(285): test(3.8, 2, 'hello') #1 {main} thrown in /Library/WebServer/Documents/book/str.php on line 281

可變引數

在 PHP 5.6 及以後的版本中,引數可包含來表示函數可接受一個可變數量的引數,可變引數將會被當作一個陣列傳遞給函數。範例如下:
<?php
function test(...$num){
    $acc = 0;
    foreach ($num as $key => $value) {
        $acc += $value;
    }
    return $acc;
}
echo test(1,2,3,4);
?>
給 test() 函數傳遞的引數 1234 在函數內部將會被當作陣列處理,執行以上程式碼的結果為:

10