首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 入門

PHP 函數完整指南:定義、參數、回傳值、變數函數、匿名函數與箭頭函數

     編輯:PHP 入門

PHP 函數完整指南

函數是程式碼復用的基本單位。PHP 提供超過 1000 內建函數,並支援使用者自訂函數、匿名函數、箭頭函數、變數函數等現代特性。本文系統整理函數定義、參數機制、回傳值、進階用法與最佳實踐。

基本定義與呼叫

<?php
// 基本語法
function greet(string $name): string {
    return "Hello, $name!";
}

// 呼叫
echo greet('World'); // Hello, World!

// 宣告提升:函數定義可在呼叫之後
sayHi();
function sayHi() { echo "Hi!\n"; }

參數機制

1. 型別宣告(PHP 7.0+)

<?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 { /* ... */ } // 預設值

2. 傳值 vs 傳參考

<?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(); }

3. 可變參數(Variadic,PHP 5.6+)

<?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";
}

4. 命名參數(PHP 8.0+)

<?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

5. 預設值限制

<?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);

匿名函數(Closure)

<?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
JSONjson_encode, json_decode, json_last_error
資料庫PDO, mysqli_*
會話session_start, session_destroy, session_regenerate_id
加密雜湊password_hash, password_verify, hash, hash_hmac, random_bytes

最佳實踐

  1. 單一職責:函數只做一件事,命名動詞開頭 getUser, calculateTotal
  2. 型別宣告:參數、回傳值皆加型別,啟用 declare(strict_types=1)
  3. 不可變參數:預設傳值,除非需修改才用 &$ref
  4. 避免全域狀態:參數傳遞優於 $GLOBALS, $_SESSION
  5. 錯誤處理:拋出異常而非回傳 false/錯誤碼
  6. 文件註解:PHPDoc 註解 /** @param int $id @return User|null */
  7. 測試性:純函數(無副作用、相同輸入固定輸出)易於單元測試

常見陷阱

陷阱說明
函數名大小寫不敏感foo() == FOO(),但建議統一小寫
預設值求值時機定義時求值,非呼叫時
匿名函數未繼承變數需 use ($var),箭頭函數自動繼承
遞迴匿名函數需 $fn = fn($n) => $n <= 1 ? 1 : $n * $fn($n-1); (PHP 8.1+ 支援)
callable 型別寬鬆字串、陣列、Closure、__invoke 物件皆通過

函數是構建程式的磚塊。掌握參數機制、閉包特性、型別系統、現代語法糖,能撰寫更清晰、安全、可測試的程式碼。善用內建函數庫,避免重複造輪子。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved