أساسيات PHP
أدوات وتقنيات تصحيح الأخطاء
أدوات وتقنيات تصحيح الأخطاء
تصحيح الأخطاء مهارة أساسية لكل مطور 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;
?>
تمرين:
- أنشئ فئة مسجل مخصصة تكتب في ملفات مختلفة بناءً على مستوى السجل (INFO، WARNING، ERROR)
- اصنع profiler يقيس وقت تنفيذ أقسام مختلفة من كودك
- اكتب دالة تصحيح تنسق المصفوفات والكائنات في جدول HTML
- أنشئ مصحح طلبات يسجل جميع بيانات الطلبات الواردة في ملف
- نفّذ مسجل استعلامات يحفظ جميع استعلامات قاعدة البيانات مع وقت التنفيذ
قائمة فحص التصحيح
عند التصحيح، قم دائماً بـ:
- تحقق من سجلات أخطاء PHP أولاً
- استخدم var_dump() أو print_r() لفحص المتغيرات
- تحقق من أنواع المتغيرات بـ gettype()
- تحقق مما إذا كانت المتغيرات معرفة بـ isset() و empty()
- استخدم error_log() لتصحيح الإنتاج
- أضف رسائل وصفية لناتج التصحيح
- اختبر الحالات الحدية (null، فارغ، صفر، قيم سالبة)
- استخدم مصحح (Xdebug) للمشكلات المعقدة
- احذف جميع كود التصحيح قبل النشر