حذر!
البثرة مغلقة الآن للتغييرات. لن تتم إضافة أي ميزات جديدة ولن يتم قبول أي تغييرات تجميلية أيضًا. التغييرات المقبولة الوحيدة هي التوافق مع إصدارات PHP الأحدث وإصلاحات المشكلات الأمنية.
حذر!
هذه هي الوثائق الخاصة بـ Pimple 3.x. إذا كنت تستخدم Pimple 1.x، فاقرأ وثائق Pimple 1.x. تعد قراءة كود Pimple 1.x أيضًا طريقة جيدة لمعرفة المزيد حول كيفية إنشاء حاوية حقن التبعية البسيطة (تركز الإصدارات الأخيرة من Pimple بشكل أكبر على الأداء).
Pimple عبارة عن حاوية حقن تبعية صغيرة لـ PHP.
قبل استخدام Pimple في مشروعك، قم بإضافته إلى ملف composer.json
الخاص بك:
$ ./composer.phar require pimple/pimple " ^3.0 "
إنشاء حاوية هو مسألة إنشاء مثيل Container
:
use Pimple Container ;
$ container = new Container ();
مثل العديد من حاويات حقن التبعية الأخرى، يدير Pimple نوعين مختلفين من البيانات: الخدمات والمعلمات .
الخدمة هي كائن يقوم بشيء ما كجزء من نظام أكبر. أمثلة على الخدمات: اتصال بقاعدة بيانات، أو محرك قوالب، أو مرسل بريد. يمكن لأي كائن عالمي تقريبًا أن يكون خدمة.
يتم تعريف الخدمات بواسطة وظائف مجهولة تقوم بإرجاع مثيل لكائن:
// define some services
$ container [ ' session_storage ' ] = fn ( $ c ) => new SessionStorage ( ' SESSION_ID ' );
$ container [ ' session ' ] = fn ( $ c ) => new Session ( $ c [ ' session_storage ' ]);
لاحظ أن الوظيفة المجهولة لديها حق الوصول إلى مثيل الحاوية الحالي، مما يسمح بالإشارات إلى خدمات أو معلمات أخرى.
نظرًا لأن الكائنات يتم إنشاؤها فقط عندما تحصل عليها، فإن ترتيب التعريفات لا يهم.
يعد استخدام الخدمات المحددة أمرًا سهلاً للغاية أيضًا:
// get the session object
$ session = $ container [ ' session ' ];
// the above call is roughly equivalent to the following code:
// $storage = new SessionStorage('SESSION_ID');
// $session = new Session($storage);
افتراضيًا، في كل مرة تحصل فيها على خدمة، يقوم Pimple بإرجاع نفس المثيل لها. إذا كنت تريد إرجاع مثيل مختلف لجميع الاستدعاءات، فقم بلف وظيفتك المجهولة باستخدام طريقة factory()
.
$ container [ ' session ' ] = $ container -> factory ( fn ( $ c ) => new Session ( $ c [ ' session_storage ' ]));
الآن، كل استدعاء إلى $container['session']
يُرجع نسخة جديدة من الجلسة.
يتيح تحديد المعلمة سهولة تكوين الحاوية الخاصة بك من الخارج وتخزين القيم العالمية:
// define some parameters
$ container [ ' cookie_name ' ] = ' SESSION_ID ' ;
$ container [ ' session_storage_class ' ] = ' SessionStorage ' ;
إذا قمت بتغيير تعريف خدمة session_storage
كما هو موضح أدناه:
$ container [ ' session_storage ' ] = fn ( $ c ) => new $ c [ ' session_storage_class ' ]( $ c [ ' cookie_name ' ]);
يمكنك الآن تغيير اسم ملف تعريف الارتباط بسهولة عن طريق تجاوز معلمة cookie_name
بدلاً من إعادة تعريف تعريف الخدمة.
نظرًا لأن Pimple يرى الوظائف المجهولة كتعريفات خدمة، فأنت بحاجة إلى تغليف الوظائف المجهولة باستخدام طريقة protect()
لتخزينها كمعلمات:
$ container [ ' random_func ' ] = $ container -> protect ( fn () => rand ());
في بعض الحالات قد ترغب في تعديل تعريف الخدمة بعد تعريفها. يمكنك استخدام التابع extend()
لتحديد تعليمات برمجية إضافية ليتم تشغيلها على خدمتك مباشرة بعد إنشائها:
$ container [ ' session_storage ' ] = fn ( $ c ) => new $ c [ ' session_storage_class ' ]( $ c [ ' cookie_name ' ]);
$ container -> extend ( ' session_storage ' , function ( $ storage , $ c ) {
$ storage ->. . .();
return $ storage ;
});
الوسيطة الأولى هي اسم الخدمة المراد توسيعها، والثانية هي وظيفة يمكنها الوصول إلى مثيل الكائن والحاوية.
إذا كنت تستخدم نفس المكتبات مرارًا وتكرارًا، فقد ترغب في إعادة استخدام بعض الخدمات من مشروع إلى المشروع التالي؛ قم بحزم خدماتك في مزود من خلال تطبيق PimpleServiceProviderInterface
:
use Pimple Container ;
class FooProvider implements Pimple ServiceProviderInterface
{
public function register ( Container $ pimple )
{
// register some services and parameters
// on $pimple
}
}
ثم قم بتسجيل الموفر على الحاوية:
$ pimple -> register ( new FooProvider ());
عند الوصول إلى كائن ما، يستدعي Pimple تلقائيًا الوظيفة المجهولة التي حددتها، والتي تقوم بإنشاء كائن الخدمة لك. إذا كنت ترغب في الحصول على وصول أولي إلى هذه الدالة، فيمكنك استخدام التابع raw()
:
$ container [ ' session ' ] = fn ( $ c ) => new Session ( $ c [ ' session_storage ' ]);
$ sessionFunction = $ container -> raw ( ' session ' );
لأسباب تاريخية، لا تقوم فئة Container
بتطبيق PSR-11 ContainerInterface
. ومع ذلك، يوفر Pimple فئة مساعدة تتيح لك فصل التعليمات البرمجية الخاصة بك عن فئة حاوية Pimple.
تتيح لك فئة PimplePsr11Container
الوصول إلى محتوى حاوية Pimple الأساسية باستخدام أساليب PsrContainerContainerInterface
:
use Pimple Container ;
use Pimple Psr11 Container as PsrContainer ;
$ container = new Container ();
$ container [ ' service ' ] = fn ( $ c ) => new Service ();
$ psr11 = new PsrContainer ( $ container );
$ controller = function ( PsrContainer $ container ) {
$ service = $ container -> get ( ' service ' );
};
$ controller ( $ psr11 );
في بعض الأحيان، تحتاج الخدمة إلى الوصول إلى العديد من الخدمات الأخرى دون التأكد من أنه سيتم استخدامها جميعًا بالفعل. في تلك الحالات، قد ترغب في أن يكون إنشاء مثيل للخدمات بطيئًا.
الحل التقليدي هو حقن حاوية الخدمة بأكملها للحصول على الخدمات المطلوبة حقًا فقط. ومع ذلك، لا يوصى بهذا لأنه يمنح الخدمات وصولاً واسعًا للغاية إلى بقية التطبيق ويخفي تبعياتها الفعلية.
يهدف ServiceLocator
إلى حل هذه المشكلة عن طريق منح الوصول إلى مجموعة من الخدمات المحددة مسبقًا أثناء إنشاء مثيل لها فقط عند الحاجة إليها بالفعل.
كما يسمح لك بإتاحة خدماتك تحت اسم مختلف عن الاسم المستخدم لتسجيلها. على سبيل المثال، قد ترغب في استخدام كائن يتوقع أن يكون مثيل EventDispatcherInterface
متاحًا تحت الاسم event_dispatcher
بينما تم تسجيل مرسل الحدث الخاص بك تحت اسم dispatcher
:
use Monolog Logger ;
use Pimple Psr11 ServiceLocator ;
use Psr Container ContainerInterface ;
use Symfony Component EventDispatcher EventDispatcher ;
class MyService
{
/**
* "logger" must be an instance of PsrLogLoggerInterface
* "event_dispatcher" must be an instance of SymfonyComponentEventDispatcherEventDispatcherInterface
*/
private $ services ;
public function __construct ( ContainerInterface $ services )
{
$ this -> services = $ services ;
}
}
$ container [ ' logger ' ] = fn ( $ c ) => new Monolog Logger ();
$ container [ ' dispatcher ' ] = fn ( $ c ) => new EventDispatcher ();
$ container [ ' service ' ] = function ( $ c ) {
$ locator = new ServiceLocator ( $ c , array ( ' logger ' , ' event_dispatcher ' => ' dispatcher ' ));
return new MyService ( $ locator );
};
قد يكون تمرير مجموعة من مثيلات الخدمات في مصفوفة غير فعال إذا كانت الفئة التي تستهلك المجموعة تحتاج فقط إلى التكرار عليها في مرحلة لاحقة، عندما يتم استدعاء إحدى طرقها. يمكن أن يؤدي أيضًا إلى مشاكل إذا كانت هناك تبعية دائرية بين إحدى الخدمات المخزنة في المجموعة والفئة التي تستهلكها.
تساعدك فئة ServiceIterator
على حل هذه المشكلات. يتلقى قائمة بأسماء الخدمات أثناء إنشاء مثيل وسيقوم باسترداد الخدمات عند تكرارها:
use Pimple Container ;
use Pimple ServiceIterator ;
class AuthorizationService
{
private $ voters ;
public function __construct ( $ voters )
{
$ this -> voters = $ voters ;
}
public function canAccess ( $ resource )
{
foreach ( $ this -> voters as $ voter ) {
if ( true === $ voter -> canAccess ( $ resource )) {
return true ;
}
}
return false ;
}
}
$ container = new Container ();
$ container [ ' voter1 ' ] = fn ( $ c ) => new SomeVoter ();
$ container [ ' voter2 ' ] = fn ( $ c ) => new SomeOtherVoter ( $ c [ ' auth ' ]);
$ container [ ' auth ' ] = fn ( $ c ) => new AuthorizationService ( new ServiceIterator ( $ c , array ( ' voter1 ' , ' voter2 ' ));