| 模式 | 觸發時機 | 適用場景 | 配置關鍵 |
|---|---|---|---|
| req (Request) | PHP 腳本啟動即連接 IDE | 全程斷點調試、開發環境 | `xdebug.start_with_request=yes` |
| jit (Just-In-Time) | 遇到斷點/錯誤/例外才連接 | 生產環境按需調試、效能分析 | `xdebug.start_with_request=trigger` + `XDEBUG_TRIGGER` |
Xdebug 透過 IDE Key (預設 `XDEBUG_SESSION`) 區分多開發者同時調試:
1. IDE 啟動偵聽 (Listen 9003) 2. 瀏覽器請求帶 XDEBUG_SESSION_START=VSCODE 3. Xdebug (Server) 主動連接 IDE:9003 → 發送封包 (feature_get, idekey=VSCODE) 4. IDE 回應 確認,發送 feature_set (breakpoint, max_depth, etc.) 5. Xdebug 執行腳本至第一行/斷點 → 發送 或 封包 (含 stack, context, variables) 6. IDE 顯示堆疊、變數,用戶操作 (Step Over, Step Into, Evaluate) → IDE 發送 / / 等命令 7. Xdebug 執行對應指令,回傳新狀態 8. 循環 5-7 直到腳本結束或用戶停止 9. 會話結束:IDE 發送 或 Xdebug 發送
| 命令 | 方向 | 用途 |
|---|---|---|
| feature_set | IDE → Xdebug | 設定編碼、最大深度、顯示隱藏屬性等 |
| breakpoint_set | IDE → Xdebug | 下斷點 (檔案、行、條件、暫時/永久) |
| breakpoint_remove | IDE → Xdebug | 移除斷點 |
| stack_get | IDE → Xdebug | 獲取當前呼叫堆疊 |
| context_get | IDE → Xdebug | 獲取作用域變數 (local, superglobals, user) |
| property_get / property_set | IDE ↔ Xdebug | 讀寫變數值 (含陣列、物件深度遍歷) |
| eval | IDE → Xdebug | 在當前上下文執行 PHP 代碼片段 |
| run / step_into / step_over / step_out | IDE → Xdebug | 控制執行流程 |
| stdout / stderr | Xdebug → IDE | 轉發 PHP 輸出到 IDE 控制台 |
// xdebug.c 片段
static void xdebug_debugger_try_connect() {
if (XG(debugger_enabled) && !XG(debugger_connected)) {
char *idekey = xdebug_get_idekey(); // 讀取 Cookie/GET/POST/ENV
if (idekey) {
xdebug_connect_to_client(idekey); // TCP connect to client_host:client_port
if (XG(debugger_connected)) {
xdebug_send_init_packet(idekey);
}
}
}
}
可見「被動等待連接」其實是 Xdebug **主動向 IDE 發起 TCP 連接**,這也是為什麼防火牆要放行「出站」而非「入站」的原因。