iT邦幫忙

2021 iThome 鐵人賽

DAY 17
0

函式就像是一個小程式一樣,把多個指令包裝在一塊,用簡單的方式就能使用

函式主要有兩種:

// 非匿名
function sum($a, $b) {
    return $a + $b;
}
echo sum(1, 2); // 3

// 匿名
$sum = function ($a, $b) {
    return $a + $b;
};
echo $sum(1, 2); // 3

函式通常是非匿名方式定義的,名稱可以自己決定,建議動詞開頭取名,取成這個函式的功能,讓人一眼就知道怎麼用這個函式

匿名函式則比較少見,你可以發現它本身是沒有名字的,有名字的是裝著它的變數


一般函式 Function

函式的參數可以設定預設值,並且在呼叫時可以不填

function sum($a, $b = 2) { // b 預設為 2
    return $a + $b;
}
echo sum(1); // 3

可以限制參數的型別 int float array...,不可使用 null

function sum(int $a, int $b) {
    return $a + $b;
}
echo sum(1, 2); // 3
echo sum(null, 2); // error

在型別前面加上 ? 表示參數可以是 null

function sum(?int $a, int $b) {
    return ($a ?? 1) + $b;
}
echo sum(null, 2); // 3

返回值也可以設定型別,void 表示不返回東西

function sum($a, $b): float {
    return $a + $b;
}
var_dump(sum(1, 2)); // float(3)

可以使用 ... 讓函式擁有可變長度參數列表

function sum($a, $b, ...$c) {
    print_r($c);
    // [0] => 3
    // [1] => 4
    // [2] => 5
    return $a + $b + array_sum($c);
}
echo sum(1, 2, 3, 4, 5); // 15

函式不能有多個返回值

function sum($a, $b) {
    return $a, $b; // syntax error
}
sum(1, 2); 

但是可以用陣列包起來,再用陣列取值的方式拿出來

function sum($a, $b) {
    return [$a, $b];
}
[$x, $y] = sum(1, 2);
echo $x, "\n"; // 1
echo $y, "\n"; // 2

使用函式時可以利用陣列解包填入參數

function sum($a, $b) {
    return $a + $b;
}
$x = [1, 2];
echo sum(...$x); // 3

匿名函式 Anonymous Function

一般函式的功能它都有,它還有一個額外的關鍵字 use,讓它可以使用外面的變數,但是是複製一份進去,並不是原本的那個

$x = 1;
$addX = function () use ($x) {
    $x++;
    echo $x, "\n"; // 2
};
$addX();
echo $x, "\n"; // 1

匿名函式可以做為函式的參數 Callback Function

function callback(callable $a) {
    $a();
}
$x = function () {
    echo 'Hello, World!';
};
callback($x); // Hello, World!

匿名函式也可以做為函式的返回值,製作閉包 Closure

function makeClosure($a) {
    return function ($b) use ($a) {
        return $a . ', ' . $b . '!';
    };
}
$closure = makeClosure('Hello'); // 把 Hello 關在裡面
echo $closure('World'); // Hello, World!

另外還有一種簡化的匿名函式:

箭頭函式 Arrow Function

會自動返回結果,不用打 return

不需要 use 就能使用外面的變數,但一樣是複製過後的

$x = 1;
$add = fn () => $x += 1;

echo $add(), "\n"; // 2
echo $x, "\n"; // 1

作用域 Scope

在函式中是不能存取外面的變數的,這個特性可以防止意外的改動

$x = 1;
function readX() {
    echo $x; // error
}
readX();

常數沒有這個限制,因為原本就改不了

const X = 1;
function readX() {
    echo X; // 1
}
readX();

加一行 global 的話就能夠修改外面的變數(建議不要這樣做)

$x = 1;
function readX() {
    global $x;
    echo $x; // 1
}
readX();

建議將變數透過參數傳入使用,這樣雖然會無法修改外面的變數,但可以讓程式比較乾淨

$x = 1;
function readX($a) {
    echo ++$a, "\n"; // 2
}
readX($x);
echo $x; // 1

可以透過傳參考 Call By Reference,在參數前加 &,使得兩個變數指向同一個記憶體位置

$x = 1;
function readX(&$a) {
    echo ++$a, "\n"; // 2
}
readX($x);
echo $x; // 2

返回值也可以設定成傳參考,函式名稱前要加 &,不論是在定義還是使用時

$x = 1;
function &readX(&$a) {
    echo ++$a, "\n"; // 2
    return $a;
}
$i = &readX($x);
echo $x, "\n"; // 2
echo $i, "\n"; // 2
$i++;
echo $x, "\n"; // 3
echo $i, "\n"; // 3

匿名函式的 use 中的參數也可以傳參考

$x = 1;
$addX = function () use (&$x) {
    $x++;
};
$addX();
echo $x; // 2

其他特性

函式中函式 Functions Within Function

函式可以在函式裡定義,而且不論在哪裡定義,都可以在全域使用

但是要執行函式(createSum)才會定義函式(sum)

function createSum() {
    function sum($a, $b) {
        return $a + $b;
    }
}
echo sum(1, 2); // error
createSum();
echo sum(1, 2); // 3

遞迴函式 Recursive Function

函式可以呼叫自己,例如製作 f(x) = x + f(x - 1)

function sum($a) {
    if ($a <= 0) {
        return 0;
    }
    return $a + sum($a - 1);
}
echo sum(10); // 55

變數函式 Variable Function

如果變數後面附加了括號,PHP 會找與值相同名稱的函式,並嘗試執行它

function sum($a, $b) {
    return $a + $b;
}
$a = 'sum';
echo $a(1, 2);

關於函式的內建函式 Function Handling Function

函式 說明 用法
function_exists() 檢查函式是否存在 function_exists($fn_name)
get_defined_functions() 查看所有已定義函式 get_defined_functions()
function createSum() {
    function sum($a, $b) {
        return $a + $b;
    }
}
var_dump(function_exists('sum')); // bool(false)
createSum();
var_dump(function_exists('sum')); // bool(true)

其他內建函式:https://www.php.net/manual/en/ref.funchand.php


上一篇
【PHP Telegram Bot】Day16 - 基礎(5):檔案讀取與寫入、cURL
下一篇
【PHP Telegram Bot】Day18 - 基礎(7):邏輯運算與流程控制
系列文
用 PHP 打造專屬於自己的 Telegram 聊天機器人吧!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言