حقن الاعتماديات التلقائي
في Webman، يُعتبر حقن الاعتماديات التلقائي ميزة اختيارية، وهذه الميزة مغلقة افتراضيًا. إذا كنت بحاجة إلى حقن الاعتماديات التلقائي، يوصى باستخدام php-di، وفيما يلي كيفية استخدام Webman مع php-di
.
التثبيت
composer require psr/container ^1.1.1 php-di/php-di ^6.3 doctrine/annotations ^1.14
قم بتعديل الإعدادات في config/container.php
، ليكون محتواها النهائي كما يلي:
$builder = new \DI\ContainerBuilder();
$builder->addDefinitions(config('dependence', []));
$builder->useAutowiring(true);
$builder->useAnnotations(true);
return $builder->build();
config/container.php
ترجع في النهاية مثالًا من حاوية متوافقة مع معيارPSR-11
. إذا كنت لا ترغب في استخدامphp-di
، يمكنك هنا إنشاء وإرجاع مثال آخر لحاوية متوافقة مع معيارPSR-11
.
حقن عبر المُنشئ
قم بإنشاء app/service/Mailer.php
(إذا لم يكن الدليل موجودًا، الرجاء إنشاؤه بنفسك) بالمحتوى التالي:
<?php
namespace app\service;
class Mailer
{
public function mail($email, $content)
{
// كود إرسال البريد الإلكتروني محذوف
}
}
محتوى app/controller/UserController.php
كما يلي:
<?php
namespace app\controller;
use support\Request;
use app\service\Mailer;
class UserController
{
private $mailer;
public function __construct(Mailer $mailer)
{
$this->mailer = $mailer;
}
public function register(Request $request)
{
$this->mailer->mail('hello@webman.com', 'Hello and welcome!');
return response('ok');
}
}
في الظروف العادية، تحتاج إلى الكود التالي لإكمال إنشاء مثال من app\controller\UserController
:
$mailer = new Mailer;
$user = new UserController($mailer);
عند استخدام php-di
، لن يحتاج المطور يدويًا إلى إنشاء Mailer
في وحدة التحكم، حيث سيقوم Webman بإنشائها تلقائيًا لك. إذا كان هناك أي اعتماديات أخرى في عملية إنشاء Mailer
، فإن Webman أيضًا سيقوم بإنشائها وحقنها تلقائيًا. لا يحتاج المطور إلى أي عمل إعداد.
ملاحظة
يجب أن تكون الأمثلة التي أنشأها الإطار أوphp-di
لتتمكن من إكمال حقن الاعتماديات التلقائي، لن تتمكن الأمثلة التي تم إنشاؤها يدويًا بواسطةnew
من إكمال حقن الاعتماديات، إذا كانت هناك حاجة إلى الحقن، فيجب استخدام واجهةsupport\Container
بدلاً من عبارةnew
، على سبيل المثال:
use app\service\UserService;
use app\service\LogService;
use support\Container;
// الأمثلة التي تم إنشاؤها بواسطة new لن تتمكن من حقن الاعتماديات
$user_service = new UserService;
// الأمثلة التي تم إنشاؤها بواسطة new لن تتمكن من حقن الاعتماديات
$log_service = new LogService($path, $name);
// الأمثلة التي أنشأتها Container يمكن حقن اعتمادياتها
$user_service = Container::get(UserService::class);
// الأمثلة التي أنشأتها Container يمكن حقن اعتمادياتها
$log_service = Container::make(LogService::class, [$path, $name]);
حقن بواسطة التعليقات التوضيحية
بالإضافة إلى حقن الاعتماديات عبر المُنشئ، يمكننا أيضًا استخدام حقن التعليقات التوضيحية. نواصل مع المثال السابق، حيث يُغير app\controller\UserController
ليصبح كما يلي:
<?php
namespace app\controller;
use support\Request;
use app\service\Mailer;
use DI\Annotation\Inject;
class UserController
{
/**
* @Inject
* @var Mailer
*/
private $mailer;
public function register(Request $request)
{
$this->mailer->mail('hello@webman.com', 'Hello and welcome!');
return response('ok');
}
}
هذا المثال يستخدم تعليق @Inject
للحقن، والتي يتم الإعلان فيها عن نوع الكائن بواسطة التعليق @var
. هذا المثال يعادل الحقن عبر المُنشئ ولكن الكود أكثر اختصارًا.
ملاحظة
لا يدعم Webman حقن معلمات وحدة التحكم قبل الإصدار 1.4.6، على سبيل المثال، الكود التالي غير مدعوم عندما يكون Webman <= 1.4.6
<?php
namespace app\controller;
use support\Request;
use app\service\Mailer;
class UserController
{
// لا يدعم الإصدار 1.4.6 حقن معلمات وحدة التحكم
public function register(Request $request, Mailer $mailer)
{
$mailer->mail('hello@webman.com', 'Hello and welcome!');
return response('ok');
}
}
حقن مُخصص عبر المُنشئ
في بعض الأحيان، قد لا تكون المعلمات المرسلة إلى المُنشئ هي مثيلات من الكائنات، ولكنها سلاسل نصية أو أرقام أو مصفوفات أو أي بيانات أخرى. على سبيل المثال، قد يحتاج مُنشئ Mailer إلى تمرير عنوان IP لخادم SMTP ورقم المنفذ:
<?php
namespace app\service;
class Mailer
{
private $smtpHost;
private $smtpPort;
public function __construct($smtp_host, $smtp_port)
{
$this->smtpHost = $smtp_host;
$this->smtpPort = $smtp_port;
}
public function mail($email, $content)
{
// كود إرسال البريد الإلكتروني محذوف
}
}
في هذه الحالة، لا يمكن استخدام حقن الاعتماديات عبر المُنشئ المبين سابقًا مباشرة، لأن php-di
لا يمكنه تحديد قيم smtp_host
و smtp_port
. في هذه الحالة، يمكن محاولة الحقن المخصص.
في config/dependence.php
(إذا كان الملف غير موجود، يرجى إنشاؤه بنفسك) بالإضافة إلى الكود التالي:
return [
// ... هنا تم تجاهل إعدادات أخرى
app\service\Mailer::class => new app\service\Mailer('192.168.1.11', 25);
];
عندها، ستستخدم الاعتماديات تلقائيًا مثال app\service\Mailer
الذي تم إنشاؤه في هذا الإعداد عند الحاجة للاعتماد.
نلاحظ أن config/dependence.php
استخدمت new
لإنشاء مثيل من فئة Mailer
، وهو أمر لا مشكلة فيه في هذا المثال، ولكن تخيل لو كانت فئة Mailer
تعتمد على فئات أخرى أو استخدمت الحقن بواسطة التعليقات التوضيحية؛ فإن استخدام new
للت初始化 لن يدعم حقن الاعتماديات. الحل هو استخدام حقن عبر واجهات مخصصة، من خلال Container::get(اسم_الفئة)
أو Container::make(اسم_الفئة, [معلمات_المُنشئ])
لتهيئة الفئة.
حقن عبر واجهات مخصصة
في المشاريع الواقعية، نفضل أن نبرمج وفقًا للواجهات، وليس الفئات المحددة. على سبيل المثال، يجب أن تستورد app\controller\UserController
واجهة app\service\MailerInterface
بدلاً من app\service\Mailer
.
تعريف واجهة MailerInterface
.
<?php
namespace app\service;
interface MailerInterface
{
public function mail($email, $content);
}
تعريف تنفيذ واجهة MailerInterface
.
<?php
namespace app\service;
class Mailer implements MailerInterface
{
private $smtpHost;
private $smtpPort;
public function __construct($smtp_host, $smtp_port)
{
$this->smtpHost = $smtp_host;
$this->smtpPort = $smtp_port;
}
public function mail($email, $content)
{
// كود إرسال البريد الإلكتروني محذوف
}
}
استيراد واجهة MailerInterface
وليس التنفيذ المحدد.
<?php
namespace app\controller;
use support\Request;
use app\service\MailerInterface;
use DI\Annotation\Inject;
class UserController
{
/**
* @Inject
* @var MailerInterface
*/
private $mailer;
public function register(Request $request)
{
$this->mailer->mail('hello@webman.com', 'Hello and welcome!');
return response('ok');
}
}
config/dependence.php
ستحدد واجهة MailerInterface
كما يلي.
use Psr\Container\ContainerInterface;
return [
app\service\MailerInterface::class => function(ContainerInterface $container) {
return $container->make(app\service\Mailer::class, ['smtp_host' => '192.168.1.11', 'smtp_port' => 25]);
}
];
عندما تحتاج الأعمال لاستخدام واجهة MailerInterface
، سيتم استخدام تنفيذ Mailer
تلقائيًا.
فائدة البرمجة على الواجهات هو أنه عند الحاجة لتغيير أحد المكونات، لا تحتاج إلى تغيير كود الأعمال، بل تحتاج فقط إلى تعديل التنفيذ المحدد في
config/dependence.php
. وهذا مفيد أيضًا في إجراء اختبارات الوحدة.
حقن مخصص آخر
يمكن أن تُعرّف config/dependence.php
بالإضافة إلى اعتماديات الفئات، قيمًا أخرى مثل السلاسل النصية أو الأرقام أو المصفوفات.
على سبيل المثال، يمكن أن تُعرّف config/dependence.php
كما يلي:
return [
'smtp_host' => '192.168.1.11',
'smtp_port' => 25
];
عندها يمكننا استخدام @Inject
لحقن smtp_host
و smtp_port
في خصائص الفئة.
<?php
namespace app\service;
use DI\Annotation\Inject;
class Mailer
{
/**
* @Inject("smtp_host")
*/
private $smtpHost;
/**
* @Inject("smtp_port")
*/
private $smtpPort;
public function mail($email, $content)
{
// كود إرسال البريد الإلكتروني محذوف
echo "{$this->smtpHost}:{$this->smtpPort}\n"; // ستخرج 192.168.1.11:25
}
}
ملاحظة:
@Inject("key")
تضع المفتاح داخل علامات الاقتباس المزدوجة
المزيد من المحتوى
يرجى الرجوع إلى دليل php-di