调试技巧

什么是调试

调试(Debugging)是发现、分析和修复程序错误的过程。良好的调试技巧是每个程序员必须掌握的基本技能,它能帮助我们快速定位问题并找到解决方案。

调试不仅仅是修复错误,更重要的是理解错误发生的原因,从而写出更好的代码。

基本调试方法

1. 使用 echo 和 print_r

最简单的调试方法就是使用 echo 语句输出变量的值。

<?php
// 基本输出调试
$name = "John";
$age = 25;

echo "调试信息:\n";
echo "姓名: $name\n";
echo "年龄: $age\n";

// 输出数组
$user = [
    'name' => 'John',
    'age' => 25,
    'email' => 'john@example.com'
];

echo "\n用户信息:\n";
print_r($user);
?>

2. 使用 var_dump()

var_dump() 提供更详细的变量信息,包括类型和长度。

<?php
// var_dump() 示例
$variables = [
    'string' => 'Hello World',
    'integer' => 42,
    'float' => 3.14,
    'boolean' => true,
    'array' => ['a', 'b', 'c'],
    'null' => null
];

foreach ($variables as $name => $value) {
    echo "\n变量 '$name' 的详细信息:\n";
    var_dump($value);
}

// 复杂结构的调试
$config = [
    'database' => [
        'host' => 'localhost',
        'port' => 3306,
        'credentials' => [
            'username' => 'admin',
            'password' => 'secret'
        ]
    ],
    'debug' => true,
    'version' => '1.0.0'
];

echo "\n配置详细信息:\n";
var_dump($config);
?>

3. 使用 die() 或 exit()

在调试时,有时候需要在某个点停止程序执行。

<?php
// die() 调试示例
function processOrder($orderData) {
    echo "开始处理订单\n";

    // 检查订单数据
    if (!isset($orderData['id'])) {
        echo "错误:订单ID缺失\n";
        var_dump($orderData);
        die("停止执行");
    }

    echo "订单ID: " . $orderData['id'] . "\n";

    // 继续处理...
    return true;
}

// 测试
$order = ['name' => 'Test Order'];
processOrder($order);
?>

高级调试技巧

1. 使用 debug_backtrace()

debug_backtrace() 可以显示函数调用的堆栈信息。

<?php
function functionA() {
    echo "在函数 A 中\n";
    functionB();
}

function functionB() {
    echo "在函数 B 中\n";
    functionC();
}

function functionC() {
    echo "在函数 C 中\n";

    echo "\n调用堆栈:\n";
    $backtrace = debug_backtrace();

    foreach ($backtrace as $trace) {
        echo "函数: " . ($trace['function'] ?? '未知') . "\n";
        echo "文件: " . ($trace['file'] ?? '未知') . "\n";
        echo "行号: " . ($trace['line'] ?? '未知') . "\n";
        echo "-------------------\n";
    }
}

// 调用链
functionA();
?>

2. 使用 debug_print_backtrace()

debug_print_backtrace() 直接输出堆栈信息。

<?php
function calculateTotal($price, $quantity) {
    echo "计算总价: $price × $quantity\n";
    $result = multiply($price, $quantity);
    return $result;
}

function multiply($a, $b) {
    echo "执行乘法: $a × $b\n";
    echo "\n调用堆栈:\n";
    debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
    return $a * $b;
}

// 调用
$total = calculateTotal(100, 5);
echo "\n结果: $total\n";
?>

3. 使用 error_log()

将调试信息记录到日志文件。

<?php
// 自定义调试函数
function debug_log($message, $context = []) {
    $timestamp = date('Y-m-d H:i:s');
    $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);

    $caller = $trace[0];
    $file = basename($caller['file']);
    $line = $caller['line'];

    $logMessage = "[$timestamp] $file:$line - $message";

    if (!empty($context)) {
        $logMessage .= " | Context: " . json_encode($context, JSON_UNESCAPED_UNICODE);
    }

    error_log($logMessage . PHP_EOL, 3, 'debug.log');
}

// 使用示例
function processUserData($userData) {
    debug_log("开始处理用户数据", ['userData' => $userData]);

    if (empty($userData['email'])) {
        debug_log("邮箱为空", ['userData' => $userData]);
        return false;
    }

    debug_log("用户数据处理完成");
    return true;
}

// 测试
$user = ['name' => 'John', 'email' => ''];
processUserData($user);
?>

调试函数封装

1. 综合调试函数

<?php
class Debugger {
    private static $enabled = true;
    private static $logFile = 'debug.log';

    // 启用/禁用调试
    public static function enable($enabled = true) {
        self::$enabled = $enabled;
    }

    // 设置日志文件
    public static function setLogFile($filename) {
        self::$logFile = $filename;
    }

    // 打印变量信息
    public static function dump($var, $label = '') {
        if (!self::$enabled) return;

        $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
        $caller = $trace[0];

        echo "<pre style='background: #f0f0f0; padding: 10px; margin: 10px; border: 1px solid #ccc;'>";
        if ($label) {
            echo "<strong>$label:</strong> ";
        }
        echo "文件: " . basename($caller['file']) . ":" . $caller['line'] . "\n";
        var_dump($var);
        echo "</pre>";
    }

    // 记录到日志
    public static function log($message, $context = []) {
        if (!self::$enabled) return;

        $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
        $caller = $trace[0];

        $timestamp = date('Y-m-d H:i:s');
        $location = basename($caller['file']) . ":" . $caller['line'];

        $logEntry = "[$timestamp] $location - $message";

        if (!empty($context)) {
            $logEntry .= " | " . json_encode($context, JSON_UNESCAPED_UNICODE);
        }

        file_put_contents(self::$logFile, $logEntry . PHP_EOL, FILE_APPEND | LOCK_EX);
    }

    // 条件调试
    public static function dumpIf($condition, $var, $label = '') {
        if ($condition && self::$enabled) {
            self::dump($var, $label);
        }
    }

    // 函数调用时间测量
    public static function measureTime($function, $args = [], $label = '') {
        if (!self::$enabled) {
            return call_user_func_array($function, $args);
        }

        $start = microtime(true);
        $result = call_user_func_array($function, $args);
        $end = microtime(true);

        $duration = round(($end - $start) * 1000, 2);
        $funcName = is_string($function) ? $function : 'anonymous_function';

        self::log("函数执行时间: {$funcName}() = {$duration}ms", $args);

        return $result;
    }

    // 内存使用情况
    public static function memoryUsage($label = '') {
        if (!self::$enabled) return;

        $memory = memory_get_usage(true);
        $peak = memory_get_peak_usage(true);

        $usage = [
            'current' => self::formatBytes($memory),
            'peak' => self::formatBytes($peak)
        ];

        if ($label) {
            self::log("内存使用 ($label)", $usage);
        } else {
            self::log("内存使用", $usage);
        }
    }

    // 格式化字节数
    private static function formatBytes($bytes) {
        $units = ['B', 'KB', 'MB', 'GB'];
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);

        $bytes /= pow(1024, $pow);
        return round($bytes, 2) . ' ' . $units[$pow];
    }

    // 清空日志文件
    public static function clearLog() {
        file_put_contents(self::$logFile, '');
    }
}

// 使用示例
function testFunction($name, $age) {
    Debugger::log("函数开始", ['name' => $name, 'age' => $age]);
    Debugger::memoryUsage("函数开始时");

    $result = "姓名: $name, 年龄: $age";

    Debugger::dump($result, "函数结果");
    Debugger::memoryUsage("函数结束时");
    Debugger::log("函数结束");

    return $result;
}

// 测试调试功能
Debugger::enable();
Debugger::clearLog();
Debugger::memoryUsage("程序开始");

$output = Debugger::measureTime('testFunction', ['John', 30], 'testFunction');
echo $output;

// 数组调试
$data = [
    'users' => [
        ['name' => 'John', 'age' => 30],
        ['name' => 'Jane', 'age' => 25]
    ],
    'total' => 2
];

Debugger::dump($data, "用户数据");
Debugger::dumpIf(isset($data['total']), $data['total'], "用户总数");
?>

2. 数据库查询调试

<?php
class DatabaseDebugger {
    private $queries = [];
    private $logQueries = false;

    public function enableQueryLogging($enable = true) {
        $this->logQueries = $enable;
    }

    public function logQuery($sql, $params = [], $executionTime = 0) {
        if (!$this->logQueries) return;

        $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
        $caller = $trace[2] ?? $trace[1] ?? [];

        $query = [
            'sql' => $sql,
            'params' => $params,
            'time' => round($executionTime * 1000, 2),
            'file' => basename($caller['file'] ?? 'unknown'),
            'line' => $caller['line'] ?? 'unknown'
        ];

        $this->queries[] = $query;

        echo "<div style='background: #f9f9f9; padding: 10px; margin: 5px; border-left: 4px solid #007cba;'>";
        echo "<strong>SQL Query:</strong> " . htmlspecialchars($sql) . "<br>";
        if (!empty($params)) {
            echo "<strong>参数:</strong> " . json_encode($params, JSON_UNESCAPED_UNICODE) . "<br>";
        }
        echo "<strong>执行时间:</strong> {$query['time']}ms<br>";
        echo "<strong>位置:</strong> {$query['file']}:{$query['line']}";
        echo "</div>";
    }

    public function getQueryCount() {
        return count($this->queries);
    }

    public function getTotalExecutionTime() {
        return array_sum(array_column($this->queries, 'time'));
    }

    public function getQueries() {
        return $this->queries;
    }

    public function printQuerySummary() {
        if (empty($this->queries)) return;

        echo "<div style='background: #e7f3ff; padding: 10px; margin: 10px; border: 1px solid #007cba;'>";
        echo "<strong>查询统计:</strong><br>";
        echo "总查询数: " . $this->getQueryCount() . "<br>";
        echo "总执行时间: " . $this->getTotalExecutionTime() . "ms<br>";
        echo "平均执行时间: " . round($this->getTotalExecutionTime() / $this->getQueryCount(), 2) . "ms";
        echo "</div>";
    }
}

// 模拟数据库类
class Database {
    private $debugger;

    public function __construct() {
        $this->debugger = new DatabaseDebugger();
        $this->debugger->enableQueryLogging(true);
    }

    public function query($sql, $params = []) {
        $start = microtime(true);

        // 模拟查询执行
        $result = $this->executeQuery($sql, $params);

        $end = microtime(true);
        $executionTime = $end - $start;

        // 记录查询
        $this->debugger->logQuery($sql, $params, $executionTime);

        return $result;
    }

    private function executeQuery($sql, $params) {
        // 模拟查询逻辑
        usleep(rand(1000, 5000));  // 模拟查询延迟
        return ['result' => 'success', 'rows' => rand(1, 10)];
    }

    public function getUsers() {
        return $this->query("SELECT * FROM users WHERE active = ?", [1]);
    }

    public function getUserById($id) {
        return $this->query("SELECT * FROM users WHERE id = ?", [$id]);
    }

    public function insertUser($name, $email) {
        return $this->query("INSERT INTO users (name, email) VALUES (?, ?)", [$name, $email]);
    }

    public function __destruct() {
        $this->debugger->printQuerySummary();
    }
}

// 使用示例
$db = new Database();

$users = $db->getUsers();
$user = $db->getUserById(1);
$db->insertUser('John Doe', 'john@example.com');
?>

Web 调试技巧

1. HTTP 请求调试

<?php
class WebDebugger {
    public static function dumpRequest() {
        echo "<div style='background: #f5f5f5; padding: 15px; margin: 10px; font-family: monospace;'>";

        // 请求信息
        echo "<h3>请求信息</h3>";
        echo "<strong>方法:</strong> " . $_SERVER['REQUEST_METHOD'] . "<br>";
        echo "<strong>URL:</strong> " . $_SERVER['REQUEST_URI'] . "<br>";
        echo "<strong>协议:</strong> " . $_SERVER['SERVER_PROTOCOL'] . "<br>";
        echo "<strong>时间:</strong> " . date('Y-m-d H:i:s') . "<br>";

        // GET 参数
        if (!empty($_GET)) {
            echo "<h3>GET 参数</h3>";
            echo "<pre>" . json_encode($_GET, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . "</pre>";
        }

        // POST 参数
        if (!empty($_POST)) {
            echo "<h3>POST 参数</h3>";
            echo "<pre>" . json_encode($_POST, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . "</pre>";
        }

        // Cookie 信息
        if (!empty($_COOKIE)) {
            echo "<h3>Cookies</h3>";
            echo "<pre>" . json_encode($_COOKIE, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . "</pre>";
        }

        // Headers
        echo "<h3>HTTP Headers</h3>";
        $headers = getallheaders();
        echo "<pre>" . json_encode($headers, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . "</pre>";

        echo "</div>";
    }

    public static function logRequest() {
        $logData = [
            'timestamp' => date('Y-m-d H:i:s'),
            'method' => $_SERVER['REQUEST_METHOD'],
            'url' => $_SERVER['REQUEST_URI'],
            'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
            'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'unknown',
            'get' => $_GET,
            'post' => $_POST,
            'files' => $_FILES
        ];

        $logMessage = json_encode($logData, JSON_UNESCAPED_UNICODE) . "\n";
        file_put_contents('requests.log', $logMessage, FILE_APPEND | LOCK_EX);
    }
}

// 使用示例
if (isset($_GET['debug']) && $_GET['debug'] == '1') {
    WebDebugger::dumpRequest();
}

WebDebugger::logRequest();
?>

2. Session 调试

<?php
class SessionDebugger {
    public static function dumpSession() {
        if (session_status() == PHP_SESSION_NONE) {
            session_start();
        }

        echo "<div style='background: #fff3cd; padding: 15px; margin: 10px; border: 1px solid #ffeaa7;'>";
        echo "<h3>Session 信息</h3>";
        echo "<strong>Session ID:</strong> " . session_id() . "<br>";
        echo "<strong>Session 状态:</strong> " . self::getSessionStatus() . "<br>";

        if (!empty($_SESSION)) {
            echo "<h4>Session 数据:</h4>";
            echo "<pre>" . json_encode($_SESSION, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . "</pre>";
        } else {
            echo "<p>Session 为空</p>";
        }

        echo "</div>";
    }

    public static function watchSession() {
        if (session_status() == PHP_SESSION_NONE) {
            session_start();
        }

        // 记录 Session 变化
        static $lastSession = null;

        if ($lastSession === null) {
            $lastSession = $_SESSION;
            return;
        }

        $changes = self::findSessionChanges($lastSession, $_SESSION);
        if (!empty($changes)) {
            echo "<div style='background: #d4edda; padding: 10px; margin: 10px; border: 1px solid #c3e6cb;'>";
            echo "<h4>Session 变化:</h4>";
            foreach ($changes as $change) {
                echo "$change<br>";
            }
            echo "</div>";
        }

        $lastSession = $_SESSION;
    }

    private static function getSessionStatus() {
        $status = session_status();
        switch ($status) {
            case PHP_SESSION_DISABLED:
                return '禁用';
            case PHP_SESSION_NONE:
                return '未启动';
            case PHP_SESSION_ACTIVE:
                return '活动';
            default:
                return '未知';
        }
    }

    private static function findSessionChanges($old, $new) {
        $changes = [];

        // 检查新增的变量
        foreach ($new as $key => $value) {
            if (!isset($old[$key])) {
                $changes[] = "新增: $key = " . json_encode($value, JSON_UNESCAPED_UNICODE);
            } elseif ($old[$key] !== $value) {
                $changes[] = "修改: $key 从 " . json_encode($old[$key], JSON_UNESCAPED_UNICODE) .
                           " 变为 " . json_encode($value, JSON_UNESCAPED_UNICODE);
            }
        }

        // 检查删除的变量
        foreach ($old as $key => $value) {
            if (!isset($new[$key])) {
                $changes[] = "删除: $key";
            }
        }

        return $changes;
    }
}

// 使用示例
if (isset($_GET['session_debug'])) {
    SessionDebugger::dumpSession();
}

SessionDebugger::watchSession();

// 设置一些 session 数据进行测试
$_SESSION['user_id'] = 123;
$_SESSION['username'] = 'JohnDoe';
$_SESSION['last_login'] = date('Y-m-d H:i:s');
?>

性能调试

1. 执行时间分析

<?php
class PerformanceProfiler {
    private $timers = [];
    private $startMemory;

    public function __construct() {
        $this->startMemory = memory_get_usage(true);
    }

    public function startTimer($name) {
        $this->timers[$name] = ['start' => microtime(true)];
    }

    public function endTimer($name) {
        if (!isset($this->timers[$name])) {
            return false;
        }

        $this->timers[$name]['end'] = microtime(true);
        $this->timers[$name]['duration'] = $this->timers[$name]['end'] - $this->timers[$name]['start'];

        return $this->timers[$name]['duration'];
    }

    public function getTimer($name) {
        return $this->timers[$name] ?? null;
    }

    public function getAllTimers() {
        return $this->timers;
    }

    public function printReport() {
        echo "<div style='background: #e8f5e9; padding: 15px; margin: 10px; border: 1px solid #4caf50;'>";
        echo "<h3>性能分析报告</h3>";

        foreach ($this->timers as $name => $timer) {
            if (isset($timer['duration'])) {
                $duration = round($timer['duration'] * 1000, 2);
                echo "<strong>$name:</strong> {$duration}ms<br>";
            }
        }

        $memoryUsage = memory_get_usage(true) - $this->startMemory;
        $peakMemory = memory_get_peak_usage(true);

        echo "<strong>内存使用:</strong> " . self::formatBytes($memoryUsage) . "<br>";
        echo "<strong>峰值内存:</strong> " . self::formatBytes($peakMemory) . "<br>";

        echo "</div>";
    }

    private function formatBytes($bytes) {
        $units = ['B', 'KB', 'MB', 'GB'];
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);

        $bytes /= pow(1024, $pow);
        return round($bytes, 2) . ' ' . $units[$pow];
    }
}

// 使用示例
$profiler = new PerformanceProfiler();

// 测试不同函数的性能
$profiler->startTimer('array_push');
$arr = [];
for ($i = 0; $i < 10000; $i++) {
    array_push($arr, $i);
}
$profiler->endTimer('array_push');

$profiler->startTimer('direct_assignment');
$arr2 = [];
for ($i = 0; $i < 10000; $i++) {
    $arr2[] = $i;
}
$profiler->endTimer('direct_assignment');

$profiler->startTimer('string_concatenation');
$str = '';
for ($i = 0; $i < 1000; $i++) {
    $str .= "item $i, ";
}
$profiler->endTimer('string_concatenation');

$profiler->startTimer('array_join');
$parts = [];
for ($i = 0; $i < 1000; $i++) {
    $parts[] = "item $i";
}
$str2 = implode(', ', $parts);
$profiler->endTimer('array_join');

$profiler->printReport();
?>

调试最佳实践

1. 调试代码的管理

<?php
class DebugManager {
    private $debugMode;
    private $environment;

    public function __construct($environment = 'production') {
        $this->environment = $environment;
        $this->debugMode = $environment === 'development';
    }

    public function isDebugMode() {
        return $this->debugMode;
    }

    public function assert($condition, $message = '') {
        if ($this->debugMode && !$condition) {
            $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
            $caller = $trace[0];

            echo "<div style='background: #ffebee; padding: 10px; margin: 10px; border: 1px solid #f44336;'>";
            echo "<strong>断言失败!</strong><br>";
            echo "文件: " . basename($caller['file']) . ":" . $caller['line'] . "<br>";
            if ($message) {
                echo "信息: $message";
            }
            echo "</div>";

            die("断言失败,停止执行");
        }
    }

    public function benchmark($description, $callback) {
        if (!$this->debugMode) {
            return $callback();
        }

        $start = microtime(true);
        $memoryBefore = memory_get_usage(true);

        $result = $callback();

        $end = microtime(true);
        $memoryAfter = memory_get_usage(true);

        $duration = round(($end - $start) * 1000, 2);
        $memoryUsed = self::formatBytes($memoryAfter - $memoryBefore);

        echo "<div style='background: #fff3e0; padding: 8px; margin: 5px; border-left: 4px solid #ff9800;'>";
        echo "<strong>$description</strong><br>";
        echo "执行时间: {$duration}ms<br>";
        echo "内存使用: $memoryUsed";
        echo "</div>";

        return $result;
    }

    private function formatBytes($bytes) {
        $units = ['B', 'KB', 'MB', 'GB'];
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);

        $bytes /= pow(1024, $pow);
        return round($bytes, 2) . ' ' . $units[$pow];
    }
}

// 全局调试管理器
$debug = new DebugManager('development');

// 使用示例
function processData($data) {
    global $debug;

    $debug->assert(!empty($data), "数据不能为空");

    return $debug->benchmark('数据处理', function() use ($data) {
        // 模拟数据处理
        $result = [];
        foreach ($data as $item) {
            $result[] = strtoupper($item);
        }
        return $result;
    });
}

// 测试
$data = ['apple', 'banana', 'cherry'];
$processed = processData($data);
print_r($processed);
?>

2. 调试技巧总结

<?php
// 调试工具函数集合
function d($var, $label = '') {
    // 开发环境调试输出
    if (defined('DEBUG_MODE') && DEBUG_MODE) {
        $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
        $caller = $trace[0];

        echo "<pre style='background: #f0f8ff; padding: 10px; margin: 10px; border: 1px solid #007cba;'>";
        if ($label) {
            echo "<strong>$label:</strong>\n";
        }
        echo "位置: " . basename($caller['file']) . ":" . $caller['line'] . "\n";
        print_r($var);
        echo "</pre>";
    }
}

function dd($var, $label = '') {
    // 调试并停止
    d($var, $label);
    die();
}

function logd($message, $context = []) {
    // 记录调试日志
    if (defined('DEBUG_MODE') && DEBUG_MODE) {
        $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
        $caller = $trace[0];

        $timestamp = date('Y-m-d H:i:s');
        $location = basename($caller['file']) . ":" . $caller['line'];

        $logMessage = "[$timestamp] $location - $message";
        if (!empty($context)) {
            $logMessage .= " | " . json_encode($context, JSON_UNESCAPED_UNICODE);
        }

        error_log($logMessage . "\n", 3, 'debug.log');
    }
}

// 使用建议
echo "<h2>PHP 调试最佳实践</h2>";
echo "<h3>1. 使用常量控制调试模式</h3>";
echo "<pre>
define('DEBUG_MODE', true);  // 开发环境
define('DEBUG_MODE', false); // 生产环境
</pre>";

echo "<h3>2. 使用合适的调试级别</h3>";
echo "<ul>";
echo "<li><strong>d() - 基本调试</strong>: 输出变量信息,继续执行</li>";
echo "<li><strong>dd() - 深度调试</strong>: 输出变量信息,停止执行</li>";
echo "<li><strong>logd() - 日志调试</strong>: 记录到日志文件,不影响页面</li>";
echo "</ul>";

echo "<h3>3. 调试策略</h3>";
echo "<ul>";
echo "<li>开发环境:开启所有调试功能</li>";
echo "<li>测试环境:开启部分调试功能</li>";
echo "<li>生产环境:关闭所有调试功能</li>";
echo "</ul>";

echo "<h3>4. 常见调试场景</h3>";
echo "<ul>";
echo "<li><strong>变量调试</strong>: 使用 d() 或 dd() 查看变量内容</li>";
echo "<li><strong>函数调试</strong>: 在函数入口和出口添加调试信息</li>";
echo "<li><strong>性能调试</strong>: 使用 microtime() 测量执行时间</li>";
echo "<li><strong>数据库调试</strong>: 记录 SQL 查询和执行时间</li>";
echo "</ul>";

echo "<h3>5. 调试安全</h3>";
echo "<ul>";
echo "<li>生产环境绝对不能显示调试信息</li>";
echo "<li>敏感信息要脱敏处理</li>";
echo "<li>日志文件要定期清理</li>";
echo "</ul>";
?>

通过本节的学习,你应该掌握了PHP调试的各种技巧,包括基本调试方法、高级调试技巧、Web调试、性能调试等。良好的调试习惯能够帮助你更快速地定位和解决问题,提高开发效率和代码质量。