函數是程式碼復用的基本單位。PHP 提供超過 1000 內建函數,並支援使用者自訂函數、匿名函數、箭頭函數、變數函數等現代特性。本文系統整理函數定義、參數機制、回傳值、進階用法與最佳實踐。
<?php
// 基本語法
function greet(string $name): string {
return "Hello, $name!";
}
// 呼叫
echo greet('World'); // Hello, World!
// 宣告提升:函數定義可在呼叫之後
sayHi();
function sayHi() { echo "Hi!\n"; }
<?php
function add(int $a, int $b): int {
return $a + $b;
}
function process(array $items, callable $callback): void { /* ... */ }
function connect(string $host, int $port = 3306): PDO { /* ... */ } // 預設值
<?php
function byValue(int $n) { $n++; }
function byRef(int &$n) { $n++; }
$x = 1;
byValue($x); echo $x; // 1
byRef($x); echo $x; // 2
// 物件預設傳參考(實為傳遞物件控制代碼副本)
$obj = new stdClass();
$obj->val = 1;
function modifyObj($o) { $o->val = 2; }
modifyObj($obj);
echo $obj->val; // 2 (物件內部狀態被修改)
// 替換物件需傳參考
function replaceObj(&$o) { $o = new stdClass(); }
<?php
function sum(int ...$numbers): int {
return array_sum($numbers);
}
echo sum(1, 2, 3, 4); // 10
// 解包陣列
$nums = [5, 6, 7];
echo sum(...$nums); // 18
// 僅最後一個參數可為 variadic
function buildQuery(string $table, string ...$columns): string {
return "SELECT " . implode(', ', $columns) . " FROM $table";
}
<?php
function createUser(
string $name,
string $email,
int $age = 18,
bool $active = true
): array {
return compact('name', 'email', 'age', 'active');
}
// 任意順序、跳過預設值
$user = createUser(
email: 'john@example.com',
name: 'John',
active: false
);
// age 自動使用預設值 18
<?php
// 預設值必須是常數表達式
function test($a = SOME_CONST, $b = [1,2,3], $c = 'str') { /* OK */ }
// function test($a = someFunc()) { /* Error */ }
<?php
// 明確回傳
function add(int $a, int $b): int {
return $a + $b;
}
// 隱含回傳 null
function logMessage(string $msg): void {
error_log($msg);
// return; // 可省略
}
// 多重回傳(陣列/物件)
function divide(int $a, int $b): array {
if ($b === 0) throw new DivisionByZeroError();
return ['quotient' => intdiv($a, $b), 'remainder' => $a % $b];
}
[$q, $r] = divide(10, 3); // 陣列解構賦值 (PHP 7.1+)
<?php
function foo() { echo "foo\n"; }
function bar() { echo "bar\n"; }
$func = 'foo';
$func(); // foo()
$func = 'bar';
$func(); // bar()
// 陣列呼叫可呼叫物件
$obj = new class { public function __invoke() { echo "invoked\n"; } };
$obj(); // invoked
// callable 型別提示
function execute(callable $callback, mixed ...$args): mixed {
return $callback(...$args);
}
execute('strlen', 'hello'); // 5
execute([$obj, 'method'], $arg);
<?php
// 基本語法
$greet = function(string $name): string {
return "Hello, $name";
};
echo $greet('World');
// 繼承外部變數
$prefix = 'Mr. ';
$greet = function(string $name) use ($prefix) {
return $prefix . $name;
};
// 依參考繼承(可修改外部變數)
$counter = 0;
$increment = function() use (&$counter) {
return ++$counter;
};
echo $increment(); // 1
echo $increment(); // 2
// 綁定物件作用域
class User {
private string $name;
public function __construct(string $name) { $this->name = $name; }
public function getGreeter(): Closure {
return function() { return "Hello, {$this->name}"; };
}
}
$user = new User('John');
$greeter = $user->getGreeter();
echo $greeter(); // Hello, John
// Closure 類別方法
$fn = fn($x) => $x * 2; // 箭頭函數自動繼承作用域
$fn = function($x) use ($y) { return $x + $y; }; // 等價
$fn = Closure::fromCallable('strlen'); // 從現有函數建立
<?php
// PHP 7.4+ 簡潔語法,自動繼承父作用域變數
$multiply = fn($x, $y) => $x * $y;
echo $multiply(3, 4); // 12
// 實務:陣列操作
$numbers = [1, 2, 3, 4, 5];
$squared = array_map(fn($n) => $n ** 2, $numbers); // [1, 4, 9, 16, 25]
$filtered = array_filter($numbers, fn($n) => $n > 3); // [4, 5]
$sum = array_reduce($numbers, fn($carry, $n) => $carry + $n, 0); // 15
// 多行箭頭函數不支援,改用匿名函數
$complex = function($x) {
$y = $x * 2;
return $y + 1;
};
| 分類 | 代表函數 |
|---|---|
| 字串 | strlen, substr, strpos, str_replace, explode, implode, trim, sprintf |
| 陣列 | array_map, array_filter, array_reduce, array_merge, array_keys, in_array |
| 檔案系統 | fopen, file_get_contents, file_put_contents, glob, scandir, pathinfo |
| 日期時間 | date, time, strtotime, DateTime, date_create, date_format |
| 正則 | preg_match, preg_replace, preg_match_all, preg_split |
| JSON | json_encode, json_decode, json_last_error |
| 資料庫 | PDO, mysqli_* |
| 會話 | session_start, session_destroy, session_regenerate_id |
| 加密雜湊 | password_hash, password_verify, hash, hash_hmac, random_bytes |
getUser, calculateTotaldeclare(strict_types=1)&$ref$GLOBALS, $_SESSION/** @param int $id @return User|null */| 陷阱 | 說明 |
|---|---|
| 函數名大小寫不敏感 | foo() == FOO(),但建議統一小寫 |
| 預設值求值時機 | 定義時求值,非呼叫時 |
| 匿名函數未繼承變數 | 需 use ($var),箭頭函數自動繼承 |
| 遞迴匿名函數 | 需 $fn = fn($n) => $n <= 1 ? 1 : $n * $fn($n-1); (PHP 8.1+ 支援) |
| callable 型別寬鬆 | 字串、陣列、Closure、__invoke 物件皆通過 |
函數是構建程式的磚塊。掌握參數機制、閉包特性、型別系統、現代語法糖,能撰寫更清晰、安全、可測試的程式碼。善用內建函數庫,避免重複造輪子。