إعادة هيكلة كود PHP القديم: من الألف إلى الياء للمبتدئين

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

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

ابدأ الدورة

إعادة هيكلة كود PHP القديم: من الألف إلى الياء

\n\n

العمل مع كود PHP القديم (legacy) هو واقع لا مفر منه للعديد من المطورين. المشاريع التي كُتبت قبل 5-10 سنوات غالباً ما تمثل "كود سباغيتي" مع متغيرات عامة، وخلط بين منطق الأعمال والعرض، وغياب التصنيف، واستخدام دوال قديمة (mysql_*, ereg، إلخ). في هذه المقالة، سنشرح نهجاً خطوة بخطوة لإعادة هيكلة كود PHP القديم، مما سيسمح بتحسين المشروع دون إيقاف تشغيله.

\n\n

لماذا تعتبر إعادة هيكلة الكود القديم صعبة؟

\n\n

المشكلة الرئيسية في الكود القديم هي غياب الاختبارات. لا يمكنك التأكد من أن التغييرات لن تعطل الوظائف الحالية. الصعوبات الإضافية:

\n\n
    \n
  • غياب التوثيق — منطق العمل غالباً ما يكون غير مفهوم
  • \n
  • خلط الطبقات — استعلامات SQL داخل قوالب HTML
  • \n
  • الحالة العامة — متغيرات يمكن الوصول إليها من أي نقطة في الكود
  • \n
  • الأنماط القديمة — استخدام register_globals، دوال mysql_*
  • \n
  • التبعيات الصلبة — إنشاء الكائنات مباشرة عبر new داخل الفئات
  • \n
\n\n

التحضير لإعادة الهيكلة: إنشاء "شبكة أمان"

\n\n

قبل تغيير الكود، يجب التأكد من أنك ستتمكن من اكتشاف الأخطاء. إليك الخطوات الإلزامية:

\n\n

1. إضافة اختبارات التوصيف

\n\n

اختبارات التوصيف (characterization tests) تثبت السلوك الحالي للكود. تُكتب بعد كتابة الكود، وتسمح بالتأكد من أن إعادة الهيكلة لم تغير السلوك.

\n\n
<?php\n// مثال على اختبار توصيف لدالة قديمة\nclass LegacyCalculatorTest extends PHPUnit\\Framework\\TestCase\n{\n    public function testCalculateTotal()\n    {\n        // تثبيت السلوك الحالي\n        $result = legacy_calculate_total(100, 0.2);\n        $this->assertEquals(120, $result);\n    }\n}\n
\n\n

2. إنشاء "غطاء" من الاختبارات

\n\n

ابدأ باختبارات التكامل التي تتحقق من سيناريوهات المستخدم الرئيسية (التسجيل، إتمام الطلب، إلخ). سيعطيك هذا ثقة أساسية أثناء إعادة الهيكلة.

\n\n

استراتيجية خطوة بخطوة لإعادة هيكلة كود PHP القديم

\n\n

نستخدم نهج "Strangler Fig Pattern" (التين الخانق) — استبدال المكونات القديمة تدريجياً بمكونات جديدة دون إيقاف تشغيل النظام.

\n\n

الخطوة 1: عزل وتغليف الحالة العامة

\n\n

المتغيرات والدوال العامة هي العدو الرئيسي لإعادة الهيكلة. ابدأ بتغليفها:

\n\n
<?php\n// قبل: دالة ومتغير عامان\n$db = mysql_connect('localhost', 'user', 'pass');\nfunction get_user($id) {\n    global $db;\n    $result = mysql_query("SELECT * FROM users WHERE id = $id", $db);\n    return mysql_fetch_assoc($result);\n}\n\n// بعد: فئة مع تبعية صريحة\nclass UserRepository {\n    private PDO $pdo;\n    \n    public function __construct(PDO $pdo) {\n        $this->pdo = $pdo;\n    }\n    \n    public function findById(int $id): ?array {\n        $stmt = $this->pdo->prepare('SELECT * FROM users WHERE id = ?');\n        $stmt->execute([$id]);\n        $user = $stmt->fetch();\n        return $user ?: null;\n    }\n}\n
\n\n

الخطوة 2: فصل المنطق عن العرض

\n\n

الكود القديم النموذجي يحتوي على SQL ومنطق PHP مباشرة داخل HTML. استخدم نمط "طريقة القالب" للفصل:

\n\n
<?php\n// قبل: كود سباغيتي في القالب\n?>\n<ul>\n<?php\n$result = mysql_query("SELECT * FROM products");\nwhile ($row = mysql_fetch_assoc($result)) {\n    echo "<li>" . $row['name'] . " - " . $row['price'] . " روبل</li>";\n}\n?>\n</ul>\n\n// بعد: فصل المنطق إلى خدمة\nclass ProductService {\n    public function __construct(private ProductRepository $repo) {}\n    \n    public function getProductList(): array {\n        return $this->repo->findAll();\n    }\n}\n\n// في القالب                

المدونات

توصيات الكتب