PHP 函數與陣列是寫出高效、優雅代碼的核心工具。PHP 函數支援預設參數、參考傳遞、可變參數、匿名函數等現代特性;而 PHP 陣列更是「有靈魂的陣列」——融合了有序陣列、關聯陣列、堆疊、佇列、集合於一身。本文深度解析函數進階特性與陣列完整操作 API。
function addPrefix(&$str, $prefix = 'PRE_') {
$str = $prefix . $str;
}
$name = 'PHP';
addPrefix($name); // $name 變為 'PRE_PHP'
addPrefix($name, 'NEW_'); // $name 變為 'NEW_PRE_PHP'
用途:修改呼叫端變數、大型資料避免複製開銷(PHP 7+ 寫時複製機制已優化,較少需要)。
function greet($name = 'Guest', $greeting = 'Hello') {
echo "$greeting, $name!";
}
greet(); // Hello, Guest!
greet('Alice'); // Hello, Alice!
greet('Bob', 'Hi'); // Hi, Bob!
// greet(greeting: 'Hey', name: 'Tom'); // PHP 8.0+ 命名參數
規則:預設參數必須在非預設參數之後;預設值必須是常數表達式(不可為變數、函式呼叫)。
function factorial(int $n): int {
if ($n <= 1) return 1;
return $n * factorial($n - 1);
}
echo factorial(5); // 120
注意:PHP 無尾呼叫優化,深度遞迴會耗盡記憶體(預設 `memory_limit` 128M),大數據遞迴改用迭代。
function sum(...$numbers): float {
return array_sum($numbers);
}
echo sum(1, 2, 3); // 6
echo sum(...[4, 5, 6]); // 15 (解包陣列)
$multiply = function($a, $b) {
return $a * $b;
};
echo $multiply(3, 4); // 12
// 閉包捕獲外部變數
$factor = 10;
$scale = function($n) use ($factor) {
return $n * $factor;
};
echo $scale(5); // 50
// 箭頭函數 (PHP 7.4+)
$scale = fn($n) => $n * $factor;
// 短語法 (PHP 5.4+)
$indexed = ['apple', 'banana', 'cherry']; // 索引陣列 0,1,2
$assoc = ['name' => 'Alice', 'age' => 25, 'city' => 'Taipei']; // 關聯陣列
// array() 傳統語法
$mixed = array(0 => 'first', 'key' => 'value', 2 => 'third');
// 陣列鍵特性:整數鍵自動遞增、字串鍵共存
$weird = [
0 => '零',
'2' => '字串鍵2', // 注意:'2' 會被轉為整數 2!
'key' => '值',
10 => '十',
11 => '十一' // 自動遞增從最大整數鍵+1 開始
];
// $weird[2] 覆蓋 '零' 變 '字串鍵2'!
// $weird[11] = '十一' (自動遞增鍵)
| 輸入鍵 | 實際儲存鍵 | 說明 |
|---|---|---|
| `0` | `0` (int) | 整數保持 |
| `'0'` | `0` (int) | 數值字串轉整數 |
| `'00'` | `'00'` (string) | 前導零保持字串 |
| `'2'` | `2` (int) | 數值字串轉整數 |
| `'key'` | `'key'` (string) | 非數值字串保持 |
| `true` | `1` (int) | 布林轉整數 |
| `false` | `0` (int) | 布林轉整數 |
| `null` | `''` (string) | Null 轉空字串 |
| `[]` | 觸發 Warning,鍵為 `''` | 陣列不可為鍵 |
$arr = [1, 2, 3];
// 尾部插入(佇列 push)
$arr[] = 4; // 最快、最常用
array_push($arr, 5, 6); // 可一次推入多個,回傳新長度
// 頭部插入(堆疊 unshift)
array_unshift($arr, 0); // [0, 1, 2, 3, 4, 5, 6],回傳新長度
// 尾部移除(堆疊 pop)
$last = array_pop($arr); // 回傳移除的值,$arr 變短
// 頭部移除(佇列 shift)
$first = array_shift($arr); // 回傳移除的值,鍵值重新索引(整數鍵從 0 開始)
$arr = ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 2];
// 鍵存在
isset($arr['a']); // true (最快,檢測 null 視為不存在)
array_key_exists('a', $arr); // true (檢測鍵是否存在,包含 null 值)
// 值存在
in_array(2, $arr); // true (嚴格模式 in_array(2, $arr, true) 檢查型別)
array_search(2, $arr); // 'b' (回傳第一個找到的鍵)
array_keys($arr, 2); // ['b', 'd'] (回傳所有匹配的鍵)
// 取得所有鍵/值
array_keys($arr); // ['a', 'b', 'c', 'd']
array_values($arr); // [1, 2, 3, 2] (重新索引 0,1,2,3)
$arr = ['a' => 1, 'b' => 2, 'c' => 3];
// foreach (最常用、支援引用修改)
foreach ($arr as $key => &$value) {
$value *= 2; // 修改原陣列值
}
unset($value); // 重要:解除引用,避免後續誤用
// 內部指標操作 (罕見,特定演算法需求)
while ($key = key($arr)) { // 取得當前鍵
$value = current($arr); // 取得當前值
next($arr); // 移動指標到下一個
}
// 重置指標
reset($arr); // 指向第一個
end($arr); // 指向最後一個
prev($arr); // 上一個
$arr = [1, 2, 2, 3, 3, 3, 'a', 'a'];
count($arr); // 8 (元素總數)
count($arr, COUNT_RECURSIVE); // 遞迴計數 (多維陣列)
array_count_values($arr); // [1=>1, 2=>2, 3=>3, 'a'=>2] (值頻率統計)
$arr = [3, 1, 2, 2, 'a', 'A', 'a'];
// 去重 (保留第一次出現的鍵值)
$unique = array_unique($arr); // [3, 1, 2, 'a', 'A'] (注意:'a' 和 'A' 不同)
// 排序 (修改原陣列、回傳 bool)
sort($arr); // 升序,重新索引鍵 0,1,2...
rsort($arr); // 降序,重新索引
asort($arr); // 升序,**保持鍵值關聯**
arsort($arr); // 降序,保持鍵值關聯
ksort($arr); // 按鍵升序
krsort($arr); // 按鍵降序
// 自然排序 (人類直覺:a1, a2, a10)
$files = ['img1.png', 'img10.png', 'img2.png'];
natsort($files); // ['img1.png', 'img2.png', 'img10.png']
natcasesort($files); // 不分大小寫自然排序
// 自定義排序
usort($arr, function($a, $b) {
return $a <=> $b; // 太空船運算子 (PHP 7+)
});
$a = ['a' => 1, 'b' => 2];
$b = ['b' => 3, 'c' => 4];
// 合併 (字串鍵:後者覆蓋;整數鍵:重新索引附加)
$merged = array_merge($a, $b); // ['a'=>1, 'b'=>3, 'c'=>4]
$mergedRec = array_merge_recursive($a, $b); // ['a'=>1, 'b'=>[2,3], 'c'=>4] (同鍵合併為陣列)
// 交集 (保留 $a 的鍵值)
$intersect = array_intersect($a, $b); // ['b' => 2] (比較值)
$intersectKey = array_intersect_key($a, $b); // ['b' => 2] (比較鍵)
// 差集 ($a 有、$b 沒有)
$diff = array_diff($a, $b); // ['a' => 1] (比較值)
$diffKey = array_diff_key($a, $b); // ['a' => 1] (比較鍵)
// 切片 (不修改原陣列)
$slice = array_slice($arr, 2, 3); // 從索引 2 取 3 個元素
$slice = array_slice($arr, -3); // 最後 3 個元素
// 隨機打亂
shuffle($arr); // 修改原陣列,重新索引鍵
// 陣列求和
$sum = array_sum([1, 2, 3.5]); // 6.5
$numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 過濾
$evens = array_filter($numbers, fn($n) => $n % 2 === 0); // [2,4,6,8,10]
// 映射
$squares = array_map(fn($n) => $n ** 2, $numbers); // [1,4,9,16,25,36,49,64,81,100]
// 歸約
$sum = array_reduce($numbers, fn($carry, $n) => $carry + $n, 0); // 55
// 鍵值同時操作 (PHP 7.4+)
$result = array_reduce($assoc, fn($carry, $value, $key) => $carry + "$key=$value;", '');
// 注意:array_map/filter 不直接傳遞鍵,需用 array_keys 配合或 foreach
| 陷阱 | 原因 | 解決方案 |
|---|---|---|
| 陣列鍵自動轉換導致覆蓋 | `'2'` → `2`,與整數鍵 `2` 衝突 | 避免混用數值字串與整數鍵;必要時用 `serialize()` 序列化鍵 |
| `foreach` 引用殘留導致最後元素被修改 | `&$value` 參考未解除 | 迴圈結束後 `unset($value)` |
| `in_array` 型別鬆散比較 | `in_array('1', [true])` 為 true | 嚴格模式:`in_array($needle, $haystack, true)` |
| `array_merge` 整數鍵重新索引 | 預設行為 | 需保持鍵用 `+` 運算子:`$a + $b` ($a 鍵優先) |
| 大陣列 `count()` 在迴圈條件中重複呼叫 | 效能浪費 | 預先存入變數:`$len = count($arr); for($i=0;$i<$len;$i++)` |
PHP 函數與陣列是語言表達力的核心:
熟練運用這些工具,能讓你用最少代碼解決最複雜的資料處理問題——這正是 PHP 「快速開發」能力的來源。