لماذا مراجعة الكود ليست مجرد "بحث عن الأخطاء"
\n\nتخيل: لقد كتبت كودًا مثاليًا. إنه يعمل، يجتاز الاختبارات، وحتى العميل راضٍ. ولكن عند مراجعة الكود، يأتي زميلك ويبدأ: "لماذا استخدمت == بدلاً من ===؟"، "هذه الدالة تقوم بـ 5 مهام في وقت واحد"، "أين معالجة الاستثناءات؟". هل يبدو هذا مألوفًا؟
في الحقيقة، مراجعة كود PHP ليست مجرد صيد للأخطاء (رغم أن ذلك جزء منها). إنها وسيلة لجعل الكود قابلًا للقراءة وآمنًا وسهل الصيانة. خاصة في PHP، حيث تراكمت على مدار 25 عامًا من التطور الكثير من "المزالق".
\n\nفي هذه المقالة، سنستعرض ما يجب فحصه في مراجعة كود PHP ليكون الكود ليس فقط فعالاً بل معيارًا للجودة. هل أنت مستعد؟ لنبدأ!
\n\n1. تحديد الأنواع والوضع الصارم
\n\nأصبحت PHP 7+ و 8 توفر أدوات قوية للتحكم في الأنواع. لكن العديد من المشاريع لا تزال تعيش في "وضع الفوضى".
\n\nما يجب فحصه:
\n\n- \n
- هل تم تحديد أنواع الوسائط والقيم المُعادة؟ إذا كانت الدالة تستقبل
intولكنك تمررstring، فهذا يستدعي النقاش. \n - هل يوجد
declare(strict_types=1);في بداية الملف؟ بدونه، سيقوم PHP بتحويل الأنواع ضمنيًا، مما يؤدي غالبًا إلى أخطاء خفية. \n
<?php\ndeclare(strict_types=1);\n\n// سيء: بدون أنواع\nfunction calculate($a, $b) {\n return $a + $b;\n}\n\n// جيد: تحديد صارم للأنواع\nfunction calculate(int $a, int $b): int {\n return $a + $b;\n}\n?>\n\n\nنصيحة لمراجعة الكود: إذا رأيت mixed أو array دون تحديد، اسأل "ما المتوقع بالضبط هنا؟".
2. الأمان: حقن SQL والبرمجة النصية عبر المواقع (XSS)
\n\nPHP مثل سكين سويسري: يحتوي على العديد من الدوال، والكثير منها خطير. خاصة في الكود القديم (Legacy).
\n\nأهم 3 علامات خطر:
\n\n- \n
- دمج النصوص في استعلامات SQL. إذا رأيت
"SELECT * FROM users WHERE id = ".$_GET['id']، فهذه صرخة استغاثة. \n - عرض البيانات دون تنقية.
echo $userInput;— مرحبًا بـ XSS. \n - تخزين كلمات المرور كنص عادي. بجدية، هذا لا يزال موجودًا. \n
<?php\n// خطير!\n$sql = "SELECT * FROM users WHERE email = '" . $email . "'";\n\n// آمن (باستخدام PDO)\n$stmt = $pdo->prepare("SELECT * FROM users WHERE email = :email");\n$stmt->execute(['email' => $email]);\n?>\n\n\nفي مراجعة كود PHP، تحقق دائمًا من التعامل مع البيانات الخارجية. أي $_GET أو $_POST أو $_COOKIE يجب أن يمر عبر عملية تنقية.
3. الالتزام بمعايير PSR
\n\nمجتمع PHP وضع معايير PSR (PHP Standards Recommendations) ليس من أجل المظهر. إنها اللغة التي يتحدث بها جميع مطوري PHP.
\n\nما يجب أن يكون في كل طلب سحب (PR):
\n\n- \n
- PSR-12 (أسلوب الترميز): مسافات بادئة بمقدار 4 مسافات، الأقواس المعقوفة في سطر جديد للكلاسات، مسافات حول العوامل. \n
- PSR-4 (التحميل التلقائي): يجب أن تتطابق مساحات الأسماء (Namespaces) مع مسار الملف. \n
- أسماء الكلاسات
StudlyCaps، الدوالcamelCase، الثوابتUPPER_CASE. \n
<?php\nnamespace App\\Service;\n\nclass UserService // PSR-4: يجب أن يكون الملف في src/Service/UserService.php\n{\n public function getUserById(int $id): ?User // camelCase\n {\n // ...\n }\n}\n?>\n\n\nحيلة مفيدة: إذا لم يكن المشروع يستخدم أدوات التنسيق التلقائي (PHP CS Fixer, PHP_CodeSniffer)، فهذه أول نقطة يجب تحسينها.
\n\n4. التعقيد والهندسة المعمارية
\n\nالكود الجيد هو الكود الذي يمكن قراءته ككتاب. أما الكود السيء فهو كفك رموز مخطوطة قديمة.
\n\nما يجب الانتباه إليه:
\n\n- \n
- طول الدالة. إذا كانت الدالة أطول من 20-30 سطرًا، فمن المحتمل أنها تفعل أكثر من شيء واحد. \n
- التعقيد الشرطي. تداخل
ifداخلifداخلif— هذه وصفة لكارثة. \n - مبدأ المسؤولية الواحدة (Single Responsibility). كل كلاس أو دالة يجب أن يكون له مسؤولية واحدة واضحة. \n
<?php\n// سيء: دالة تفعل كل شيء\nfunction processUserData(array $data): array {\n // التحقق من الصحة\n // الحفظ في قاعدة البيانات\n // إرسال بريد إلكتروني\n // إنشاء سجل\n return $result;\n}\n\n// جيد: فصل المسؤوليات\nfunction validateUserData(array $data): bool { /* ... */ }\nfunction saveUserToDatabase(array $data): int { /* ... */ }\nfunction sendWelcomeEmail(int $userId): void { /* ... */ }\n?>\n\n\nنصيحة لمراجعة الكود: إذا استغرقت أكثر من دقيقتين لفهم ما تفعله دالة معينة، فهذه علامة على أنها بحاجة إلى إعادة هيكلة.
\n\n5. معالجة الأخطاء والاستثناءات
\n\nالكود الذي لا يتعامل مع الأخطاء بشكل صحيح هو قنبلة موقوتة. في PHP، يمكن أن يؤدي تجاهل الاستثناءات إلى تعطل التطبيق بالكامل أو تسريب معلومات حساسة.
\n\nما يجب فحصه:
\n\n- \n
- هل يتم استخدام كتل
try-catchبشكل مناسب؟ خاصة عند التعامل مع قواعد البيانات أو واجهات برمجة التطبيقات (API). \n - هل يتم تسجيل الأخطاء (Logging) بشكل صحيح؟ لا تكتفِ بـ
echo $e->getMessage();في بيئة الإنتاج. \n - هل يتم إخفاء تفاصيل الأخطاء عن المستخدم؟ لا تعرض أبدًا تتبع الاستثناءات (Stack Trace) للمستخدم النهائي. \n
<?php\n// سيء: تجاهل الخطأ\n$result = mysqli_query($conn, $sql);\n\n// جيد: معالجة الاستثناءات\nfunction getUserByEmail(string $email): ?User {\n try {\n $stmt = $this->pdo->prepare(\"SELECT * FROM users WHERE email = :email\");\n $stmt->execute(['email' => $email]);\n return $stmt->fetchObject(User::class) ?: null;\n } catch (PDOException $e) {\n // سجل الخطأ\n error_log(\"Database error: \" . $e->getMessage());\n // وأعد قيمة آمنة\n return null;\n }\n}\n?>\n\n\nفي مراجعة كود PHP، تأكد من أن كل عملية قد تفشل يتم تغليفها بمعالجة مناسبة للاستثناءات.
\n\n6. الأداء واستعلامات قاعدة البيانات
\n\nPHP ليس بطيئًا بطبيعته، لكن الكود السيء يمكن أن يجعله كذلك. استعلامات قاعدة البيانات غير المحسّنة هي السبب الأكثر شيوعًا لمشاكل الأداء.
\n\nما يجب فحصه:
\n\n- \n
- هل يتم استخدام الفهارس (Indexes) بشكل صحيح؟ استعلامات بدون
WHEREعلى أعمدة مفهرسة تسبب مسحًا كاملاً للجدول. \n - هل يتم جلب بيانات أكثر من اللازم؟
SELECT *في تطبيق كبير هو كارثة أداء. \n - هل يتم استخدام التخزين المؤقت (Caching)؟ إذا كان نفس الاستعلام يتكرر، يجب تخزين النتيجة. \n
- مشكلة N+1. إذا كنت تجلب بيانات في حلقة، فهذه علامة خطر. \n
<?php\n// سيء: مشكلة N+1\n$users = $db->query(\"SELECT * FROM users\")->fetchAll();\nforeach ($users as &$user) {\n $user['posts'] = $db->query(\"SELECT * FROM posts WHERE user_id = {$user['id']}\")->fetchAll();\n}\n\n// جيد: استعلام واحد مع JOIN\n$users = $db->query(\"\n SELECT u.*, p.* \n FROM users u \n LEFT JOIN posts p ON u.id = p.user_id\n\")->fetchAll();\n?>\n\n\nنصيحة لمراجعة الكود: استخدم أدوات مثل Xdebug أو Blackfire لتحليل الأداء في مراجعة الكود.
\n\n7. الاختبارات والتغطية
\n\nالكود بدون اختبارات هو مثل سيارة بدون فرامل. قد تعمل، لكنك لا تريد أن تكون فيها عند حدوث خطأ.
\n\nما يجب فحصه:
\n\n- \n
- هل توجد اختبارات للكود الجديد؟ كل دالة أو كلاس جديد يجب أن يكون له اختبارات. \n
- هل تغطي الاختبارات الحالات الحدية؟ ليس فقط المسار السعيد (Happy Path). \n
- هل يتم استخدام
assertأوexpectExceptionبشكل صحيح؟ تأكد من أن الاختبارات تختبر السلوك الفعلي. \n
<?php\nuse PHPUnit\\Framework\\TestCase;\n\nclass UserServiceTest extends TestCase\n{\n public function testGetUserByIdReturnsUserWhenFound(): void\n {\n $service = new UserService($this->createMock(UserRepository::class));\n $user = $service->getUserById(1);\n $this->assertInstanceOf(User::class, $user);\n }\n\n public function testGetUserByIdReturnsNullWhenNotFound(): void\n {\n $service = new UserService($this->createMock(UserRepository::class));\n $user = $service->getUserById(999);\n $this->assertNull($user);\n }\n}\n?>\n\n\nنصيحة لمراجعة الكود: إذا رأيت كودًا بدون اختبارات، اطلب إضافتها قبل الموافقة على طلب السحب (PR).
\n\n8. قابلية الصيانة والتوثيق
\n\nالكود الذي تكتبه اليوم سيقرأه شخص آخر (أو أنت بعد 6 أشهر). اجعل هذه التجربة ممتعة.
\n\nما يجب فحصه:
\n\n- \n
- هل الأسماء واضحة؟
$dataو$tempو$xهي أسماء سيئة. استخدم أسماء تعبر عن المحتوى. \n - هل توجد تعليقات (Comments) حيثما لزم الأمر؟ ليس لكل سطر، ولكن للخوارزميات المعقدة أو القرارات غير البديهية. \n
- هل تمت إزالة الكود المعلق؟ الكود المعلق يسبب فوضى ويشتت الانتباه. \n
- هل يوجد توثيق للواجهات العامة (API)؟ خاصة إذا كان الكود سيُستخدم من قبل مطورين آخرين. \n
<?php\n// سيء: أسماء غير واضحة\nfunction calc($a, $b) {\n return $a * $b + $a / $b;\n}\n\n// جيد: أسماء واضحة وتعليق يشرح المنطق\n/**\n * حساب التكلفة الإجمالية بعد الخصم والضريبة\n *\n * @param float $price السعر الأساسي\n * @param float $discount نسبة الخصم (0-1)\n * @param float $taxRate نسبة الضريبة (0-1)\n * @return float التكلفة الإجمالية\n */\nfunction calculateTotalCost(float $price, float $discount, float $taxRate): float {\n $priceAfterDiscount = $price * (1 - $discount);\n $taxAmount = $priceAfterDiscount * $taxRate;\n return $priceAfterDiscount + $taxAmount;\n}\n?>\n\n\nنصيحة لمراجعة الكود: تخيل أنك تقرأ الكود لأول مرة. إذا استغرقت وقتًا طويلاً لفهمه، فهذا يعني أنه يحتاج إلى تحسين.
\n\nالخلاصة: قائمة مراجعة كود PHP النهائية
\n\nإليك ملخص سريع يمكنك استخدامه كقائمة مراجعة في مراجعة الكود التالية:
\n\n- \n
- تحديد الأنواع:
declare(strict_types=1)وأنواع الوسائط والقيم المُعادة. \n - الأمان: لا لحقن SQL، لا لـ XSS، تشفير كلمات المرور. \n
- معايير PSR: PSR-12 للترميز، PSR-4 للتحميل التلقائي. \n
- التعقيد: دوال قصيرة، مسؤولية واحدة، لا للتعقيد الشرطي المفرط. \n
- معالجة الأخطاء: استخدام
try-catch، تسجيل الأخطاء، إخفاء التفاصيل عن المستخدم. \n - الأداء: استعلامات محسّنة، استخدام الفهارس، تجنب N+1. \n
- الاختبارات: تغطية الحالات الحدية، اختبارات للكود الجديد. \n
- قابلية الصيانة: أسماء واضحة، تعليقات مفيدة، لا للكود المعلق. \n
مراجعة كود PHP ليست مجرد إجراء شكلي. إنها استثمار في جودة الكود وسلامة الفريق. كل ساعة تقضيها في مراجعة الكود توفر لك ساعات من تصحيح الأخطاء لاحقًا.
\n\nهل لديك نقاط إضافية تفحصها في مراجعة الكود؟ شاركها في التعليقات!