PHP 基礎面試題精選:六大核心考點深度解析
面試不只是背答案,要理解「為什麼這樣設計」、「邊界情況如何」、「實務最佳實踐是什麼」。本文精選 6 道高頻基礎題,附標準答案、陷阱分析、進階延伸。
一、輸出函數差異:echo、print、print_r、printf、sprintf、var_dump
| 函數/語句 | 類型 | 返回值 | 參數數量 | 可輸出類型 | 典型用途 |
| echo | 語句 | 無 | 多個 (逗號分隔) | 純量 | 一般輸出、效能最好 |
| print | 語句 | 永遠 1 | 單個 | 純量 | 需在表達式中輸出 |
| print_r() | 函數 | bool (第二參數 true 時回傳字串) | 1-2 | 所有 (陣列/物件結構化) | 除錯輸出陣列結構 |
| printf() | 函數 | 輸出長度 | 格式化字串 + 多參數 | 純量 | 格式化輸出 (C 風格) |
| sprintf() | 函數 | 格式化字串 | 同 printf | 純量 | 取得格式化字串不直接輸出 |
| var_dump() | 函數 | 無 | 多個 | 所有 (含類型、長度) | 深度除錯、類型檢查 |
陷阱與進階
echo 'a', 'b' (逗號) 比 echo 'a' . 'b' (點號) 快,無臨時字串分配
print_r($arr, true) 回傳字串,可記錄日誌或進一步處理
var_dump 顯示 string(5) "hello" 含長度,print_r 僅顯示值
- 物件輸出:
var_dump 顯示私有屬性,print_r 不顯示 (除非實作 __debugInfo)
二、禁用 Cookie 時 Session 傳遞方案與過期設置
Session ID 傳遞四大方案
| 方案 | 原理 | 缺點 | 適用場景 |
| URL 附加 SID | session_id() 透明附加到連結 | 全站無純靜態頁、URL 醜陋、安全風險 (記錄洩露) | 舊系統相容 |
| 隱藏表單欄位 | <input name="PHPSESSID" value="..."> | 不支援 <a> 連結跳轉、POST 專用 | 表單密集應用 |
| php.ini 設定 | session.use_trans_sid = 1 | 同 URL 方案、需重啟 PHP、共享主機不可改 | 全站強制啟用 |
| 手動儲存 (檔案/DB/Redis) | 自行管理 Session ID 關聯 | 開發成本高、需處理並發、過期清理 | 分散式 Session、特殊需求 |
Session 過期設置 (兩種方式)
<?php
// 方式 1:setCookie 同步 Session Cookie 過期
session_start();
setcookie(session_name(), session_id(), time() + 3600, '/'); // 1 小時
// 方式 2:session_set_cookie_params (需在 session_start 前)
session_set_cookie_params(3600); // 秒
session_start();
// 關鍵:GC 機制由 gc_probability / gc_divisor 控制 (預設 1/100 = 1% 機率觸發)
// 手動清理舊 Session 檔案更可靠
?>
三、獲取檔案內容的四種方法
| 方法 | 函數 | 支援協議 | 特點 | 適用場景 |
| 1 | file_get_contents() | HTTP/HTTPS/FTP/本地 | 簡單、整檔讀入記憶體、支援 stream context (POST/Header) | 中小檔案、簡單 GET/POST |
| 2 | fopen() + fgets() | HTTP/本地 | 流式讀取、記憶體友好、僅 GET | 大檔案、逐行處理 |
| 3 | fsockopen() | TCP/UDP (原始 Socket) | 完整控制 Header/Body、可實作任意協議 | 自定義協議、教學、底層除錯 |
| 4 | cURL (libcurl) | HTTP/HTTPS/FTP/IMAP/POP3/SMTP... | 功能最全:並發、代理、SSL、認證、限流、多執行緒 | 生產環境 HTTP 客戶端首選 |
cURL 必檢項
<?php
// php.ini 檢查
extension=curl // 必須啟用
// 實際代碼最小範例
$ch = curl_init('https://api.example.com/data');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_SSL_VERIFYPEER => true, // 生產必開
]);
$response = curl_exec($ch);
if ($response === false) throw new Exception(curl_error($ch));
curl_close($ch);
?>
四、isset()、empty()、is_null() 三大判斷函數徹底比較
<?php
$undefined; // 未定義
$null = null; // null
$emptyStr = ''; // 空字串
$zero = 0; // 整數 0
$zeroStr = '0'; // 字串 0
$false = false; // 布林 false
$emptyArr = []; // 空陣列
$tests = [
'undefined' => $undefined, // 會觸發 Notice
'null' => $null,
'emptyStr' => $emptyStr,
'zero' => $zero,
'zeroStr' => $zeroStr,
'false' => $false,
'emptyArr' => $emptyArr,
];
echo "=== isset ===\n";
foreach ($tests as $k => $v) {
// isset 不觸發 Notice,檢查「已定義且非 null」
echo "$k: " . (isset($v) ? 'true' : 'false') . "\n";
}
echo "\n=== empty ===\n";
foreach ($tests as $k => $v) {
// empty 不觸發 Notice,檢查「為空值」: "", 0, "0", null, false, [], 未定義
echo "$k: " . (empty($v) ? 'true' : 'false') . "\n";
}
echo "\n=== is_null ===\n";
foreach ($tests as $k => $v) {
// 僅檢查 === null,未定義觸發 Notice
echo "$k: " . (is_null($v) ? 'true' : 'false') . "\n";
}
?>
結果對照表
| 值 | isset | empty | is_null | 直接判斷 (if $v) |
| 未定義 | false (無 Notice) | true (無 Notice) | Notice + true | Notice + false |
| null | false | true | true | false |
| "" | true | true | false | false |
| 0 | true | true | false | false |
| "0" | true | true | false | false |
| false | true | true | false | false |
| [] | true | true | false | false |
最佳實踐
- 檢查變數**是否存在且非 null** →
isset()
- 檢查**是否為空值** (含未定義) →
empty()
- 精確檢查 **=== null** →
is_null() (確定變數已定義)
- 避免直接
if ($v) 當變數可能未定義
五、strlen() vs mb_strlen():中文長度計算陷阱
<?php
$str = '中文'; // UTF-8,每字 3 位元組
echo strlen($str); // 6 (位元組數)
echo mb_strlen($str, 'UTF-8'); // 2 (字元數)
// GB2312 環境
// strlen = 4 (每字 2 位元組)
// mb_strlen($str, 'GB2312') = 2
?>
關鍵配置
php.ini 必須啟用:extension=mbstring
- 內部編碼設定:
mb_internal_encoding('UTF-8') (建議在 bootstrap 統一設定)
- 資料庫連線、HTML meta、檔案儲存、PHP 內部**全鏈路 UTF-8**
六、獲取客戶端 IP 地址
<?php
// 基礎獲取
$ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
// 或
$ip = getenv('REMOTE_ADDR') ?: 'unknown';
// 代理/負載均衡環境:需檢查 X-Forwarded-For / X-Real-IP
function getRealIp(): string {
$headers = [
'HTTP_X_FORWARDED_FOR', // 可能包含多個 IP: client, proxy1, proxy2
'HTTP_X_REAL_IP', // Nginx proxy_set_header
'HTTP_CLIENT_IP',
'REMOTE_ADDR'
];
foreach ($headers as $header) {
if (!empty($_SERVER[$header])) {
$ips = explode(',', $_SERVER[$header]);
return trim($ips[0]); // 取最左邊 (原始客戶端)
}
}
return 'unknown';
}
// ⚠️ 安全警示:Header 可偽造,僅信任已知代理層傳入的 Header
// 正確做法:Nginx 實際 IP → 設定 X-Real-IP → PHP 僅信任該 Header
?>
基礎題考驗的是「基本功是否扎實、邊界是否想過、坑是否踩過」。建議每題都能:寫出正確代碼 → 解釋原理 → 指出陷阱 → 給出生產建議,才算真正掌握。