حقن التبعية (Dependency Injection) في PHP للمبتدئين

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

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

ابدأ الدورة

ما هو حقن التبعية في PHP ولماذا هو مهم؟

\n\n

تخيل أنك تبني منزلاً. بدلاً من أن تصنع كل لبنة بنفسك، يمكنك ببساطة طلبها واستخدامها جاهزة. حقن التبعية (DI) في البرمجة يعمل بنفس المبدأ — أنت لا تنشئ الكائنات داخل الفئة، بل تحصل عليها من الخارج. هذا يجعل الكود الخاص بك مرنًا، قابلاً للاختبار، وسهل الفهم.

\n\n

في PHP، كما في أي لغة كائنية التوجه، غالبًا ما تعتمد الفئات على فئات أخرى. تنشأ المشكلة عندما يتم إنشاء التبعيات مباشرة داخل الفئة — وهذا ما يسمى الاقتران المحكم (tight coupling). يحل حقن التبعية هذه المشكلة عن طريق تمرير التبعيات من الخارج.

\n\n

المشكلة بدون حقن التبعية

\n

لنأخذ مثالًا نموذجيًا حيث تقوم فئة UserService بإنشاء كائن قاعدة البيانات بنفسها:

\n\n
<?php\nclass Database {\n    public function query($sql) {\n        // منطق الاستعلام\n        return "النتيجة: " . $sql;\n    }\n}\n\nclass UserService {\n    private $db;\n    \n    public function __construct() {\n        // اقتران محكم — الفئة تنشئ التبعية بنفسها\n        $this->db = new Database();\n    }\n    \n    public function getUser($id) {\n        return $this->db->query("SELECT * FROM users WHERE id = $id");\n    }\n}\n\n$service = new UserService();\necho $service->getUser(1);\n?>
\n\n

مشاكل هذا الأسلوب:

\n
    \n
  • لا يمكن استبدال Database بتنفيذ آخر (مثلًا للاختبارات)
  • \n
  • صعوبة الاختبار — لا يمكن استخدام كائن وهمي (mock)
  • \n
  • يصبح الكود مترابطًا ويصعب توسيعه
  • \n
\n\n

الحل: حقن التبعية عبر المُنشئ

\n

الآن سنعيد كتابة نفس الفئة باستخدام حقن التبعية:

\n\n
<?php\nclass UserService {\n    private $db;\n    \n    // يتم تمرير التبعية من الخارج\n    public function __construct(Database $db) {\n        $this->db = $db;\n    }\n    \n    public function getUser($id) {\n        return $this->db->query("SELECT * FROM users WHERE id = $id");\n    }\n}\n\n// إنشاء التبعية بشكل منفصل\n$database = new Database();\n$service = new UserService($database);\necho $service->getUser(1);\n?>
\n\n

الآن UserService لا يعرف كيف يتم إنشاء Database. إنه ببساطة يستخدم ما تم تمريره إليه. وهذا هو حقن التبعية.

\n\n

أنواع حقن التبعية في PHP

\n

هناك ثلاث طرق رئيسية لحقن التبعيات. دعنا نستعرض كل منها مع أمثلة.

\n\n

1. الحقن عبر المُنشئ (Constructor Injection)

\n

الطريقة الأكثر شيوعًا والموصى بها. يتم تمرير التبعيات عند إنشاء الكائن عبر المُنشئ.

\n\n
<?php\nclass Logger {\n    public function log($message) {\n        echo "[LOG]: " . $message;\n    }\n}\n\nclass OrderProcessor {\n    private $logger;\n    \n    // التبعية في المُنشئ\n    public function __construct(Logger $logger) {\n        $this->logger = $logger;\n    }\n    \n    public function process($order) {\n        // معالجة الطلب\n        $this->logger->log("تمت معالجة الطلب: " . $order);\n    }\n}\n\n$logger = new Logger();\n$processor = new OrderProcessor($logger);\n$processor->process("الطلب #123");\n?>
\n\n

المزايا: التبعية متاحة دائمًا، الكائن دائمًا في حالة صالحة. العيوب: إذا كان هناك العديد من التبعيات، قد يصبح المُنشئ ضخمًا.

\n\n

2. الحقن عبر المُحدد (Setter Injection)

\n

يُستخدم عندما تكون التبعية اختيارية أو تحتاج إلى استبدالها أثناء عمل الكائن.

\n\n
<?php\nclass MailService {\n    private $transport;\n    \n    // مُحدد للتبعية\n    public function setTransport($transport) {\n        $this->transport = $transport;\n    }\n    \n    public function send($to, $mess                

المدونات

توصيات الكتب