أساسيات PHP

أدوات وتقنيات تصحيح الأخطاء

13 دقيقة الدرس 28 من 45

أدوات وتقنيات تصحيح الأخطاء

تصحيح الأخطاء مهارة أساسية لكل مطور PHP. فهم الأدوات والتقنيات المتاحة سيساعدك على تحديد المشكلات وإصلاحها بسرعة وكفاءة.

var_dump() و print_r()

الدوال الأساسية لتصحيح الأخطاء في PHP:

<?php $user = [ 'name' => 'John Doe', 'email' => 'john@example.com', 'age' => 30, 'active' => true ]; // var_dump() - يظهر معلومات النوع والقيمة var_dump($user); // الناتج: // array(4) { // ["name"]=> string(8) "John Doe" // ["email"]=> string(16) "john@example.com" // ["age"]=> int(30) // ["active"]=> bool(true) // } // print_r() - أكثر قابلية للقراءة، بدون معلومات النوع print_r($user); // الناتج: // Array // ( // [name] => John Doe // [email] => john@example.com // [age] => 30 // [active] => 1 // ) // الإرجاع كنص بدلاً من الطباعة $output = print_r($user, true); ?>
نصيحة: استخدم var_dump() عندما تحتاج لرؤية أنواع المتغيرات و print_r() عندما تحتاج لناتج أكثر قابلية للقراءة.

ناتج تصحيح محسّن

أنشئ دالة تصحيح مخصصة لتنسيق أفضل:

<?php function debug($data, $label = 'تصحيح') { echo "<div style='background:#f4f4f4;border:1px solid #ccc;padding:10px;margin:10px 0;'>"; echo "<strong>$label:</strong><br>"; echo "<pre>"; print_r($data); echo "</pre>"; echo "</div>"; } // الاستخدام $database = ['host' => 'localhost', 'user' => 'root']; debug($database, 'إعدادات قاعدة البيانات'); // تصحيح مع إيقاف (إيقاف التنفيذ) function dd($data, $label = 'تصحيح وإيقاف') { debug($data, $label); die(); } dd($database); // يظهر الناتج ويتوقف ?>

error_log() للإنتاج

استخدم error_log() للتصحيح في الإنتاج دون عرض معلومات للمستخدمين:

<?php // تسجيل بسيط error_log("محاولة تسجيل دخول المستخدم"); // تسجيل المتغيرات $userId = 123; error_log("معرّف المستخدم: " . $userId); // تسجيل المصفوفات والكائنات $user = ['id' => 123, 'name' => 'John']; error_log("بيانات المستخدم: " . print_r($user, true)); // التسجيل في ملف محدد error_log("رسالة مخصصة\n", 3, "/path/to/custom.log"); // التسجيل مع الطابع الزمني function logDebug($message, $data = null) { $timestamp = date('Y-m-d H:i:s'); $logMessage = "[$timestamp] $message"; if ($data !== null) { $logMessage .= "\n" . print_r($data, true); } error_log($logMessage); } logDebug("معالجة الطلب", ['order_id' => 456, 'amount' => 99.99]); ?>
ملاحظة: استخدم دائماً error_log() للتصحيح في الإنتاج. لا تستخدم أبداً var_dump() أو print_r() في كود الإنتاج.

debug_backtrace()

احصل على معلومات حول مكدس الاستدعاءات لتتبع من أين يتم استدعاء الدوال:

<?php function levelOne() { levelTwo(); } function levelTwo() { levelThree(); } function levelThree() { $trace = debug_backtrace(); echo "<pre>"; print_r($trace); echo "</pre>"; // تتبع مبسط foreach ($trace as $i => $call) { echo "خطوة $i: "; echo $call['function'] ?? 'main'; if (isset($call['file'])) { echo " في " . basename($call['file']) . ":" . $call['line']; } echo "\n"; } } levelOne(); // الناتج: // خطوة 0: levelThree في script.php:10 // خطوة 1: levelTwo في script.php:6 // خطوة 2: levelOne في script.php:2 ?>

get_defined_vars()

اطلع على جميع المتغيرات المتاحة في النطاق الحالي:

<?php $username = 'john'; $email = 'john@example.com'; $age = 30; // الحصول على جميع المتغيرات المعرفة $allVars = get_defined_vars(); echo "<pre>"; print_r($allVars); echo "</pre>"; // التحقق من وجود متغير محدد if (array_key_exists('username', $allVars)) { echo "اسم المستخدم معرّف"; } ?>

إضافة Xdebug

Xdebug إضافة PHP قوية لتصحيح الأخطاء والتنميط:

<?php // تثبيت Xdebug (عبر سطر الأوامر) // pecl install xdebug // التفعيل في php.ini: // zend_extension=xdebug.so // xdebug.mode=debug // xdebug.start_with_request=yes // var_dump() أفضل مع Xdebug $data = [ 'users' => [ ['id' => 1, 'name' => 'John'], ['id' => 2, 'name' => 'Jane'] ] ]; var_dump($data); // منسق بشكل جميل مع الألوان // تتبعات المكدس مع Xdebug function errorFunction() { trigger_error("خطأ تجريبي", E_USER_ERROR); } errorFunction(); // يظهر تتبع مكدس مفصل ?>
نصيحة: توفر Xdebug ناتج ملون ومنسق ويمكن دمجها مع IDEs لتصحيح الأخطاء خطوة بخطوة مع نقاط التوقف.

تصحيح نقاط التوقف مع Xdebug و IDE

ضع نقاط توقف في IDE الخاص بك (VS Code، PhpStorm) لإيقاف التنفيذ مؤقتاً:

<?php // إعداد Xdebug في php.ini // xdebug.mode=debug // xdebug.client_host=127.0.0.1 // xdebug.client_port=9003 function calculateTotal($items) { $total = 0; foreach ($items as $item) { // ضع نقطة توقف هنا في IDE $total += $item['price'] * $item['quantity']; } return $total; } $items = [ ['name' => 'كتاب', 'price' => 15.99, 'quantity' => 2], ['name' => 'قلم', 'price' => 2.99, 'quantity' => 5] ]; $total = calculateTotal($items); // عند الوصول لنقطة التوقف، يمكنك: // - فحص المتغيرات ($total, $item) // - المرور عبر الكود سطراً بسطر // - تقييم التعبيرات // - عرض مكدس الاستدعاءات ?>

تصحيح الاستعلامات لـ MySQL

صحح استعلامات قاعدة البيانات بفعالية:

<?php // تسجيل جميع الاستعلامات function debugQuery($sql, $params = []) { $timestamp = date('Y-m-d H:i:s'); $logMessage = "[$timestamp] SQL: $sql"; if (!empty($params)) { $logMessage .= "\nParams: " . json_encode($params); } error_log($logMessage); } // مثال على الاستخدام $sql = "SELECT * FROM users WHERE email = ? AND status = ?"; $params = ['john@example.com', 'active']; debugQuery($sql, $params); // تنفيذ الاستعلام $stmt = $pdo->prepare($sql); $stmt->execute($params); // التحقق من الأخطاء if ($stmt->errorCode() !== '00000') { $error = $stmt->errorInfo(); error_log("خطأ SQL: " . $error[2]); } // الحصول على الاستعلام المنفذ (مع mysqli) $mysqli = new mysqli('localhost', 'user', 'pass', 'database'); mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); $query = "SELECT * FROM users WHERE id = 1"; $result = $mysqli->query($query); // التحقق من آخر استعلام error_log("آخر استعلام: " . $mysqli->info); ?>

تنميط الأداء

قياس وقت التنفيذ واستخدام الذاكرة:

<?php // قياس وقت التنفيذ $startTime = microtime(true); // كودك هنا for ($i = 0; $i < 1000000; $i++) { // عملية ما } $endTime = microtime(true); $executionTime = $endTime - $startTime; echo "وقت التنفيذ: " . number_format($executionTime, 4) . " ثانية"; // قياس استخدام الذاكرة $startMemory = memory_get_usage(); $data = range(1, 100000); $endMemory = memory_get_usage(); $memoryUsed = $endMemory - $startMemory; echo "الذاكرة المستخدمة: " . number_format($memoryUsed / 1024 / 1024, 2) . " ميجابايت"; // ذروة استخدام الذاكرة echo "ذروة الذاكرة: " . number_format(memory_get_peak_usage() / 1024 / 1024, 2) . " ميجابايت"; ?>

فئة Profiler

أنشئ profiler قابل لإعادة الاستخدام لتتبع الأداء:

<?php class Profiler { private static $timers = []; private static $memory = []; public static function start($label) { self::$timers[$label] = microtime(true); self::$memory[$label] = memory_get_usage(); } public static function end($label) { if (!isset(self::$timers[$label])) { return "المؤقت '$label' لم يبدأ"; } $time = microtime(true) - self::$timers[$label]; $memory = memory_get_usage() - self::$memory[$label]; return [ 'label' => $label, 'time' => number_format($time, 4) . 's', 'memory' => number_format($memory / 1024, 2) . 'KB' ]; } public static function report() { echo "<h3>تقرير الأداء</h3>"; echo "<table border='1'>"; echo "<tr><th>العملية</th><th>الوقت</th><th>الذاكرة</th></tr>"; foreach (self::$timers as $label => $startTime) { $result = self::end($label); echo "<tr>"; echo "<td>{$result['label']}</td>"; echo "<td>{$result['time']}</td>"; echo "<td>{$result['memory']}</td>"; echo "</tr>"; } echo "</table>"; } } // الاستخدام Profiler::start('database_query'); // تنفيذ استعلام قاعدة البيانات sleep(1); // محاكاة العمل $result = Profiler::end('database_query'); print_r($result); Profiler::start('file_processing'); // معالجة الملفات sleep(2); // محاكاة العمل Profiler::end('file_processing'); Profiler::report(); ?>

تصحيح الطلب/الاستجابة

صحح طلبات واستجابات HTTP:

<?php // تسجيل جميع بيانات الطلب function logRequest() { $log = [ 'method' => $_SERVER['REQUEST_METHOD'], 'url' => $_SERVER['REQUEST_URI'], 'headers' => getallheaders(), 'get' => $_GET, 'post' => $_POST, 'files' => $_FILES, 'cookies' => $_COOKIE, 'session' => $_SESSION ?? [], 'ip' => $_SERVER['REMOTE_ADDR'] ]; error_log("الطلب: " . print_r($log, true)); } // تسجيل الاستجابة function logResponse($data, $statusCode = 200) { $log = [ 'status' => $statusCode, 'data' => $data, 'headers' => headers_list() ]; error_log("الاستجابة: " . print_r($log, true)); } // الاستخدام logRequest(); $response = ['success' => true, 'message' => 'تم إنشاء الطلب']; logResponse($response, 201); ?>

نصائح وأفضل ممارسات التصحيح

<?php // 1. استخدم رسائل سجل وصفية error_log("معالجة الدفع للطلب رقم " . $orderId); // جيد error_log("خطوة 1"); // سيء // 2. أضف سياق للسجلات function logWithContext($message, $context = []) { $contextStr = empty($context) ? '' : ' | السياق: ' . json_encode($context); error_log($message . $contextStr); } logWithContext("فشل تسجيل دخول المستخدم", ['email' => 'user@example.com', 'ip' => '192.168.1.1']); // 3. استخدم تصحيح مشروط define('DEBUG', true); function debugLog($message, $data = null) { if (!DEBUG) { return; } echo "<pre>[DEBUG] $message\n"; if ($data !== null) { print_r($data); } echo "</pre>"; } debugLog("تم تحميل بيانات المستخدم", $userData); // 4. أنشئ فحوصات وضع التصحيح if (isset($_GET['debug']) && $_GET['debug'] === 'true') { ini_set('display_errors', 1); error_reporting(E_ALL); } // 5. سجل دخول/خروج الطرق function processOrder($orderId) { error_log("دخول: processOrder($orderId)"); try { // منطق معالجة الطلب $result = true; error_log("خروج: processOrder($orderId) - نجاح"); return $result; } catch (Exception $e) { error_log("خروج: processOrder($orderId) - خطأ: " . $e->getMessage()); throw $e; } } ?>
تحذير: احذف أو عطّل كود التصحيح قبل النشر في الإنتاج. ناتج التصحيح يمكن أن يكشف معلومات حساسة ويبطئ تطبيقك.

Chrome DevTools لتصحيح AJAX

صحح طلبات AJAX في المتصفح:

<?php // جانب الخادم (PHP API) header('Content-Type: application/json'); $data = [ 'success' => true, 'message' => 'تم استرجاع البيانات', 'data' => [/* بياناتك */] ]; // إضافة معلومات تصحيح في التطوير if (DEBUG) { $data['debug'] = [ 'query_time' => 0.045, 'queries' => ['SELECT * FROM users', 'SELECT * FROM orders'], 'memory' => memory_get_usage() ]; } echo json_encode($data, JSON_PRETTY_PRINT); // تصحيح جانب العميل: // 1. افتح Chrome DevTools (F12) // 2. اذهب إلى تبويب Network // 3. انقر على طلب AJAX // 4. اعرض تبويبات Headers، Preview، Response ?>

سيناريوهات التصحيح الشائعة

<?php // السيناريو 1: متغير فارغ أو غير متوقع $username = $_POST['username'] ?? null; var_dump($username); // تحقق من القيمة الفعلية var_dump(isset($username)); // هل هو معرّف؟ var_dump(empty($username)); // هل هو فارغ؟ // السيناريو 2: مشكلات بنية المصفوفة $users = getUsersFromDatabase(); echo "العدد: " . count($users) . "\n"; echo "العنصر الأول: "; print_r($users[0] ?? 'لا توجد عناصر'); // السيناريو 3: الدالة لا تعيد القيمة المتوقعة function getTotal($items) { $total = 0; foreach ($items as $item) { error_log("العنصر: " . print_r($item, true)); $total += $item['price']; } error_log("الإجمالي النهائي: $total"); return $total; } // السيناريو 4: الشرط لا يعمل $age = "25"; // نص، وليس عدد صحيح if ($age === 25) { // خطأ - مقارنة صارمة echo "بالغ"; } var_dump($age, gettype($age)); // تصحيح مشكلات النوع // السيناريو 5: مشكلات مسار include/require $includePath = __DIR__ . '/includes/config.php'; echo "محاولة التضمين: $includePath\n"; echo "الملف موجود: " . (file_exists($includePath) ? 'نعم' : 'لا') . "\n"; include $includePath; ?>
تمرين:
  1. أنشئ فئة مسجل مخصصة تكتب في ملفات مختلفة بناءً على مستوى السجل (INFO، WARNING، ERROR)
  2. اصنع profiler يقيس وقت تنفيذ أقسام مختلفة من كودك
  3. اكتب دالة تصحيح تنسق المصفوفات والكائنات في جدول HTML
  4. أنشئ مصحح طلبات يسجل جميع بيانات الطلبات الواردة في ملف
  5. نفّذ مسجل استعلامات يحفظ جميع استعلامات قاعدة البيانات مع وقت التنفيذ

قائمة فحص التصحيح

عند التصحيح، قم دائماً بـ:
  • تحقق من سجلات أخطاء PHP أولاً
  • استخدم var_dump() أو print_r() لفحص المتغيرات
  • تحقق من أنواع المتغيرات بـ gettype()
  • تحقق مما إذا كانت المتغيرات معرفة بـ isset() و empty()
  • استخدم error_log() لتصحيح الإنتاج
  • أضف رسائل وصفية لناتج التصحيح
  • اختبر الحالات الحدية (null، فارغ، صفر، قيم سالبة)
  • استخدم مصحح (Xdebug) للمشكلات المعقدة
  • احذف جميع كود التصحيح قبل النشر