مراجعة كود PHP: 8 أشياء أساسية يجب على كل مطور التحقق منها

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

لماذا مراجعة الكود ليست مجرد "بحث عن الأخطاء"

\n\n

تخيل: لقد كتبت كودًا مثاليًا. إنه يعمل، يجتاز الاختبارات، وحتى العميل راضٍ. ولكن عند مراجعة الكود، يأتي زميلك ويبدأ: "لماذا استخدمت == بدلاً من ===؟"، "هذه الدالة تقوم بـ 5 مهام في وقت واحد"، "أين معالجة الاستثناءات؟". هل يبدو هذا مألوفًا؟

\n\n

في الحقيقة، مراجعة كود PHP ليست مجرد صيد للأخطاء (رغم أن ذلك جزء منها). إنها وسيلة لجعل الكود قابلًا للقراءة وآمنًا وسهل الصيانة. خاصة في PHP، حيث تراكمت على مدار 25 عامًا من التطور الكثير من "المزالق".

\n\n

في هذه المقالة، سنستعرض ما يجب فحصه في مراجعة كود PHP ليكون الكود ليس فقط فعالاً بل معيارًا للجودة. هل أنت مستعد؟ لنبدأ!

\n\n

1. تحديد الأنواع والوضع الصارم

\n\n

أصبحت PHP 7+ و 8 توفر أدوات قوية للتحكم في الأنواع. لكن العديد من المشاريع لا تزال تعيش في "وضع الفوضى".

\n\n

ما يجب فحصه:

\n\n
    \n
  • هل تم تحديد أنواع الوسائط والقيم المُعادة؟ إذا كانت الدالة تستقبل int ولكنك تمرر string، فهذا يستدعي النقاش.
  • \n
  • هل يوجد declare(strict_types=1); في بداية الملف؟ بدونه، سيقوم PHP بتحويل الأنواع ضمنيًا، مما يؤدي غالبًا إلى أخطاء خفية.
  • \n
\n\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 دون تحديد، اسأل "ما المتوقع بالضبط هنا؟".

\n\n

2. الأمان: حقن SQL والبرمجة النصية عبر المواقع (XSS)

\n\n

PHP مثل سكين سويسري: يحتوي على العديد من الدوال، والكثير منها خطير. خاصة في الكود القديم (Legacy).

\n\n

أهم 3 علامات خطر:

\n\n
    \n
  • دمج النصوص في استعلامات SQL. إذا رأيت "SELECT * FROM users WHERE id = ".$_GET['id']، فهذه صرخة استغاثة.
  • \n
  • عرض البيانات دون تنقية. echo $userInput; — مرحبًا بـ XSS.
  • \n
  • تخزين كلمات المرور كنص عادي. بجدية، هذا لا يزال موجودًا.
  • \n
\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 يجب أن يمر عبر عملية تنقية.

\n\n

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
\n\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\n

4. التعقيد والهندسة المعمارية

\n\n

الكود الجيد هو الكود الذي يمكن قراءته ككتاب. أما الكود السيء فهو كفك رموز مخطوطة قديمة.

\n\n

ما يجب الانتباه إليه:

\n\n
    \n
  • طول الدالة. إذا كانت الدالة أطول من 20-30 سطرًا، فمن المحتمل أنها تفعل أكثر من شيء واحد.
  • \n
  • التعقيد الشرطي. تداخل if داخل if داخل if — هذه وصفة لكارثة.
  • \n
  • مبدأ المسؤولية الواحدة (Single Responsibility). كل كلاس أو دالة يجب أن يكون له مسؤولية واحدة واضحة.
  • \n
\n\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\n

5. معالجة الأخطاء والاستثناءات

\n\n

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

\n\n

ما يجب فحصه:

\n\n
    \n
  • هل يتم استخدام كتل try-catch بشكل مناسب؟ خاصة عند التعامل مع قواعد البيانات أو واجهات برمجة التطبيقات (API).
  • \n
  • هل يتم تسجيل الأخطاء (Logging) بشكل صحيح؟ لا تكتفِ بـ echo $e->getMessage(); في بيئة الإنتاج.
  • \n
  • هل يتم إخفاء تفاصيل الأخطاء عن المستخدم؟ لا تعرض أبدًا تتبع الاستثناءات (Stack Trace) للمستخدم النهائي.
  • \n
\n\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\n

6. الأداء واستعلامات قاعدة البيانات

\n\n

PHP ليس بطيئًا بطبيعته، لكن الكود السيء يمكن أن يجعله كذلك. استعلامات قاعدة البيانات غير المحسّنة هي السبب الأكثر شيوعًا لمشاكل الأداء.

\n\n

ما يجب فحصه:

\n\n
    \n
  • هل يتم استخدام الفهارس (Indexes) بشكل صحيح؟ استعلامات بدون WHERE على أعمدة مفهرسة تسبب مسحًا كاملاً للجدول.
  • \n
  • هل يتم جلب بيانات أكثر من اللازم؟ SELECT * في تطبيق كبير هو كارثة أداء.
  • \n
  • هل يتم استخدام التخزين المؤقت (Caching)؟ إذا كان نفس الاستعلام يتكرر، يجب تخزين النتيجة.
  • \n
  • مشكلة N+1. إذا كنت تجلب بيانات في حلقة، فهذه علامة خطر.
  • \n
\n\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\n

7. الاختبارات والتغطية

\n\n

الكود بدون اختبارات هو مثل سيارة بدون فرامل. قد تعمل، لكنك لا تريد أن تكون فيها عند حدوث خطأ.

\n\n

ما يجب فحصه:

\n\n
    \n
  • هل توجد اختبارات للكود الجديد؟ كل دالة أو كلاس جديد يجب أن يكون له اختبارات.
  • \n
  • هل تغطي الاختبارات الحالات الحدية؟ ليس فقط المسار السعيد (Happy Path).
  • \n
  • هل يتم استخدام assert أو expectException بشكل صحيح؟ تأكد من أن الاختبارات تختبر السلوك الفعلي.
  • \n
\n\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\n

8. قابلية الصيانة والتوثيق

\n\n

الكود الذي تكتبه اليوم سيقرأه شخص آخر (أو أنت بعد 6 أشهر). اجعل هذه التجربة ممتعة.

\n\n

ما يجب فحصه:

\n\n
    \n
  • هل الأسماء واضحة؟ $data و $temp و $x هي أسماء سيئة. استخدم أسماء تعبر عن المحتوى.
  • \n
  • هل توجد تعليقات (Comments) حيثما لزم الأمر؟ ليس لكل سطر، ولكن للخوارزميات المعقدة أو القرارات غير البديهية.
  • \n
  • هل تمت إزالة الكود المعلق؟ الكود المعلق يسبب فوضى ويشتت الانتباه.
  • \n
  • هل يوجد توثيق للواجهات العامة (API)؟ خاصة إذا كان الكود سيُستخدم من قبل مطورين آخرين.
  • \n
\n\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
  1. تحديد الأنواع: declare(strict_types=1) وأنواع الوسائط والقيم المُعادة.
  2. \n
  3. الأمان: لا لحقن SQL، لا لـ XSS، تشفير كلمات المرور.
  4. \n
  5. معايير PSR: PSR-12 للترميز، PSR-4 للتحميل التلقائي.
  6. \n
  7. التعقيد: دوال قصيرة، مسؤولية واحدة، لا للتعقيد الشرطي المفرط.
  8. \n
  9. معالجة الأخطاء: استخدام try-catch، تسجيل الأخطاء، إخفاء التفاصيل عن المستخدم.
  10. \n
  11. الأداء: استعلامات محسّنة، استخدام الفهارس، تجنب N+1.
  12. \n
  13. الاختبارات: تغطية الحالات الحدية، اختبارات للكود الجديد.
  14. \n
  15. قابلية الصيانة: أسماء واضحة، تعليقات مفيدة، لا للكود المعلق.
  16. \n
\n\n

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

\n\n

هل لديك نقاط إضافية تفحصها في مراجعة الكود؟ شاركها في التعليقات!

المدونات

توصيات الكتب