函數參數的各種語法特征?
一、函數的基本語法
語法
function functionName(類型限定 參數列表) : 返回值類型
{
}
案例:計算兩個數之和。
function sum (int $a, int $b) : string
{
return $a + $b;
}
echo sum(1, 2); // 3
二、函數的分類
2.1 命名函數
命名函數自動提升到腳本頂部,在全局任何地方都能調用。// 按函數名稱調用
demo1('殘破的蛋蛋');
// 聲明一個demo1函數
function demo1($name) {
echo "My name is ${name}.";
}
以上代碼會輸出:My name is 殘破的蛋蛋.2.2 匿名函數
沒有指定具體函數名稱的函數叫匿名函數,也叫閉包函數。$var = function () {
// TODO
}
以上聲明的就是一個匿名函數,它需要把函數賦給一個變量,然后通過變量去調用。$demo2 = function () {
echo "Hello World!";
}
$demo2(); // Hello World!
匿名函數通過變量調用,以上結果為:Hello World!。三、函數的參數
3.1 必選參數
function person1 (string $name) : string
{
return "Hello, ${name}!";
}
echo person1('殘破的蛋蛋')."<br>"; // Hello, 殘破的蛋蛋!
echo person1(123)."<br>"; // Hello, 123!
echo person1(true)."<br>"; // 報錯
上述第三次函數調用報錯的原因是:當限定了傳入的參數類型為字符串時,標量(單值)會自動轉換成字符串,但是布爾型、數組、類是無法自動轉換的。3.2 可選參數
在定義函數的時候聲明了參數,如果在調用的時候沒有指定參數或者是少指定了參數,那么就會出現缺少參數的報錯。在PHP中,支持函數的默認方式調用,即為函數的參數指定一個默認值,在調用函數的過程中如果沒有指定參數的值,那么在函數中會使用參數的默認值。function person2 (string $name, int $age = 20, string $sex = "男") {
echo "我的名字是:${name},年齡:${age}歲,性別:${sex}。<br>";
}
// 我的名字是:殘破的蛋蛋,年齡:20歲,性別:男。
person2('殘破的蛋蛋');
在上述案例中我們確實為person2()函數聲明了三個參數,但是我們只傳了一個參數,其他兩個參數都使用的是默認值。當調用函數傳參的過程中,實參和形參是按照參數傳遞的順序一一對應的,如果實參個數少于形參,則后面的形參不會被傳值。當使用默認參數時,必須放在非默認參數的后面,否則可能會導致函數不會按照預期的執行。3.3 不定參數
語法
function functionName (...$args) {
// TODO
}
function person3 () {
// 獲取傳遞給函數的所有變量數組
$args = func_get_args();
// 遍歷每一個傳入的參數
foreach ($args as $key => $arg) {
$num = $key + 1;
echo "第${num}個參數是:${arg}<br>";
}
}
person3('殘破的蛋蛋', 30, '男');
// 第1個參數是:殘破的蛋蛋
// 第2個參數是:30
// 第3個參數是:男
從PHP5.6以后,可以不使用func_get_args()函數獲取可變參數,使用“…”運算符來實現可變長度的函數。function person4 (...$args) {
print_r($args);
}
person4('殘破的蛋蛋', 30, '男'); // Array ( [0] => 殘破的蛋蛋 [1] => 30 [2] => 男 )
這是一個非常實用的功能,當一個函數的參數過多時,可以不用逐一地傳遞參數,實用可變參數就可以傳參了。四、函數的返回值
通常情況下,函數只允許有一個返回值,原則是“單值”返回的,如果想返回多值怎么辦?那么只能在返回值的類型上打主意了,可以通過以下方法來操作。4.1 返回一個數組
function success () : array
{
return ['status' => 1, 'message' => '驗證成功'];
}
$res = demo1();
echo $res['status'] ? $res['message'] : '驗證失敗!'; // 驗證成功!
4.2 返回一個對象
function user () : object
{
return new class () {
public $name = 'admin';
public $email = 'admin@abc.cn';
};
}
$user = user();
printf("name = %s,email = %s", $user->name, $user->email); // name = admin,email = admin@abc.cn
4.3 序列化字符串
4.3.1 php內置的序列化函數
如果有一些數據需要進行網絡傳輸或保存到文件或數據表中的時候要用到序列化函數。如果這個序列化的數據只在php程序中使用,應該使用php內置的方法就可以了。function result() : string
{
return serialize(['status' => 1, 'message' => '驗證成功']);
}
echo result(); // a:2:{s:6:"status";i:1;s:7:"message";s:12:"驗證成功";}
在php中使用時要還原成原來的類型,也就說反序列化:$arr = unserialize($str);
print_r($arr); // Array ( [status] => 1 [message] => 驗證成功 )
4.3.2 JSON格式字符串
將數據轉為通用的JSON格式字符串,這樣的話就可以與其他語言進行數據交換了,例如:JS,JAVA…function demo4() : string
{
// JSON_UNESCAPED_UNICODE 顯示中文,否則顯示的是編碼過的中文字符
// \u9a8c\u8bc1\u6210\u529f
return json_encode(['status' => 1, 'message' => '驗證成功'], JSON_UNESCAPED_UNICODE);
}
$str = demo4();
echo $str; // {"status":1,"message":"驗證成功"}
如果當前腳本接收到一個前端或其它接口發送過來的json格式的數據,可以使用json_decode進行解析。解析的目的是將外部的json還原成php能夠處理的數據類型。$res = json_decode($str);
// 默認將外部的JSON解析成Object類型。
var_dump($res);
printf('status = %d, message = %s<hr>',$res->status, $res->message);
結果:
如果不用對象的方式訪問,也可以給json_decode()函數傳入第二個參數:true。$res = json_decode($str, true);
printf('status = %d, message = %s<hr>',$res['status'], $res['message']);
結果:
五、函數的作用域
在JS中作用域有三種:全局、函數、塊作用域,而在PHP中,只有全局和函數一種作用域。全局變量也稱為外部變量,是定義在函數外部的。它的作用域從變量定義處開始。$name = '殘破的蛋蛋'; // 聲明一個$name的全局變量
$email = '826350863@qq.com'; // 聲明一個$email的全局變量
// 聲明一個user函數
function user () {
echo "我的名字是:${name},郵箱是:${email}";
}
// 調用函數
user();
結果:
以上結果我們發現報錯了,這是因為在上面的代碼中,在函數user()外面聲明了兩個全局變量$name和$email,但是在PHP中,不能直接在函數中使用全局變量,所以在user()函數中使用的變量$name和$email相當于新聲明的兩個變量,并且沒有被賦值,是兩個空值,所以會報錯。在函數中如果要使用全局變量可以使用global關鍵字或者$GLOBALS關鍵字。如下所示:function user1 () {
// 在函數內部使用global關鍵字引入全局變量,多個變量之間用逗號隔開
global $name, $email;
echo "我的名字是:${name},郵箱是:${email}";
}
user1(); // 我的名字是:殘破的蛋蛋,郵箱是:826350863@qq.com
function user2 () {
// 在函數內部使用global關鍵字引入全局變量,多個變量之間用逗號隔開
echo "我的名字是:{$GLOBALS['name']},郵箱是:{$GLOBALS['email']}";
}
user2();
以上兩個函數user1()和user2()都可以正常的輸出結果:我的名字是:殘破的蛋蛋,郵箱是:826350863@qq.com。在$GLOBALS數組中,每一個變量都是一個元素,變量名就是它的鍵名,變量值就是對應的鍵值。$GLOBALS是一個超全局變量。六、閉包
匿名函數就是閉包(官方手冊寫的),閉包可以訪問函數外部的自由變量/父級作用域的變量。$demo2 = function () use ($name, $email) {
return sprintf('name = %s<br>email = %s', $name, $email);
};
echo $demo2();
結果
閉包支持引用傳參:參數前加&,示例如下:echo "當前name的值是:${name}<br>";
$demo3 = function ($myName) use (&$name) {
// 閉包中將引用參數更新后,會實時映射到外部的原始參數中
$name = $myName;
echo "現在name的值是:${name}<br>";
};
echo $demo3('拤碎的蛋蛋');
// 輸出:
// 當前name的值是:殘破的蛋蛋
// 現在name的值是:拤碎的蛋蛋
結果
閉包use禁止使用以下三種參數:超全局不讓用$_GET
$this
與當前參數重名不讓用
閉包經常用作函數的返回值,示例如下:// 閉包經常用作函數的返回值
function demo4 ($site) {
return function ($color) use ($site) {
return sprintf('<h3 style="color:%s">%s</h3>', $color, $site);
};
}
第一種調用方式:var_dump(demo4('PHP中文網'));
$closure = demo4('PHP中文網');
echo $closure('red');
第二種調用方式:// 通過高階函數調用:柯里化
echo demo4('PHP中文網')('red');
結果:
七、回調函數
回調函數是指調用函數時傳遞的不是一個標準的變量,而是將另外一個函數作為參數傳遞到調用的函數中。call_user_func_array()調用回調函數,并把一個數組作為回調函數的參數。語法:
call_user_func_array ( callable $callback , array $param_arr ) : mixed
案例
class Person {
// 實例方法
public function getName(string $name) : string
{
return "My name is ${name},";
}
public static function age(int $age): string
{
return "年齡是:${age}歲。";
}
}
// 調用實例方法
// 注意,這里必須是要實例化的,除非是static
$str = call_user_func_array(['Person', 'getName'], ['殘破的蛋蛋']);
// 調用靜態方法
$str .= call_user_func_array(['Person', 'age'], [18]);
// 下面的用法跟上面相同
// $str .= call_user_func_array('Person::age', [18]);
echo $str; // My name is 殘破的蛋蛋,年齡是:18歲。
八、靜態變量
通常函數中的變量隨著函數的調用結束就會自動銷毀了,通過下面的案例我們可以得出這個結論:function demo1 () {
$i = 1;
echo "$i <br>";
$i++;
}
demo1(); // 1
demo1(); // 1
demo1(); // 1
demo1(); // 1
以上代碼,無論調用多少次demo1()函數結果都是輸出1,說明在第2、3、4次調用函數中并沒有執行到$i++,每次函數調用都是從$i = 1開始的。如果我們想要讓結果保留到下次調用,那么就需要使用到靜態變量了,示例如下:function demo2 () {
static $i = 1;
echo "$i <br>";
$i++;
}
demo2(); // 1
demo2(); // 2
demo2(); // 3
demo2(); // 4
以上結果分別輸出了1、2、3、4,說明函數中的靜態變量不會隨函數調用結束而消失,而是進入到了下一次的函數調用中,這種場景可以應用在函數的多次調用中的數據共享/數據通信。