الواجهات في البرمجة الكائنية هي توأم الفئات المجرده ( PHP Abstract Classes ) تتشابه معها في تعريف الطرق مجرده ( PHP Abstract Methods ) ولكن تختلف عنها في بعض التفاصيل.
صيغة الواجهه Interface Syntax interface name{ //abstract تعريف طرق مجرده بدون استخدام الكلمة //يتم تعريف الطرق بدون كود قابل للتنفيذ } class classname implements name { //إعادة تعريف الطرق المجرده الخاصة بالواجهة مع إضافة كود قابل للتنفيذ //تعريف الطرق الخاصة بالفئة نفسها } خصائص الواجهات : يتم تعريف الواجهات باستخدام الكلمة interface يتم تعريف طرق مجرده داخل الواجهه ولكن بدون استخدام الكلمة abstract ، وبدون كود فهي مجرده يجب أن تكون حدود الرؤية ( PHP Visibility ) عامة public فقط يتم تطبيق الواجهات على الفئات باستخدام الكلمة implements يتم إعاده تعريف الطرق بعد تطبيق الواجهة داخلة الفئة مع إضافة كود قابل للتنفيذ الواجهات يتم تطبيقها ( Implementation ) على الفئات وليس توريثها ، لذلك يمكن تطبيق أكثر من واجهة على الفئة نفسها. لكن يمكن أن ترث واجهه واجهه أخرى أو واجهات متعدده. لايمكن استخدام المُنشِئات ( PHP Constructors ) داخل الواجهات ، فكما تعرف أن الواجهات مثل الفئات المجرده لايتم إنشاء كائنات منها مباشرةً ، ومهمة المُنشِئات في الأساس هي عمل خصائص افتراضية للكائنات المشتقة من الفئة. إذا تم تعريف متغير ( خاصية ) property داخل الواجهة ، يجب تخصيص قيمة له وهذا إلزامي . وفي هذه الحالة فإننا نتحدث عن الثوابت ( PHP Constants ) لايمكن استخدام الخصائص الساكنة ( PHP Static Properties ) والطرق الساكنة ( PHP Static Methods) دخل الواجهات. يجب استخدام نفس الطرق المجرده كاملة داخل الفئة دون حذف أو تعديل. فالكود التالي غير صحيح interface name{ public function FunctionName($value='') { # code... } } class classname implements name { //خطأ تعريف الطرق بدون تمرير الوسائط public function FunctionName() { # code... } } ماهي الواجهات وكيف يمكن استخدامها؟ببساطه !! عارف لما يقولك ” دي مجرد واجهه “. الواجهه عباره عن شيئ لا يحتوي على تفاصيل داخليه.. تخيل واجهة ماركت يمكن تركيبها لماركت خاص بالهواتف المحمولة أو تركيبها لماركت ملابس. دعنا نتحدث بشكل تقني أكثر.
إذا كنت قد قرأت عن الفئات المجرده فلابد أنك تذكر أن من خصائصها أنها تُعتَبر بمثابة عقد ( Contract ) بحيث من يكتب هذا العقد يمكنه أن يفرض سلوك ما على الطرف الآخر ويستطيع إجباره على الطريقة أو الشكل الذي سيؤدي به هذا السلوك مع امكانية اضافة تعديل بسيط على صيغة العقد (تمرير وسائط اضافية لها قيمة عند اعادة تعريف الطرق في الفئات الوارثة). وهذا يتشابه كثيراً مع الواجهات، فهي الأخري بمثابة عقد لكن عقد ملزم لمن يستخدم العقد ولا يستطيع التعديل عليه .
هناك أيضاً اختلاف بسيط وهو أنه كما نعرف أن الفئات المجرده تُستخدم للتوريث لذلك بشكل بديهي فإن الفئات مرتبطة ببعض لأنها ترث بعضها الأخر . أما الواجهات يتم تطبيقها ( Implementation ) وليس توريثها ، إذاً يمكن تطبيقها على أي فئه ولا يشترط أن تكون هذه الفئات مرتبطه ببعضها البعض.أو يمكن أن نطلق عليها قانون وعلى من يختار الانضمام إلى الفئة التي تطبق هذا القانون ، أن يطبق القانون بحذافيره.
صيغة أخرى :
الواجهات عبارة عن سلوك ما يمكن تطبيقه على أكثر من فئة بغض النظر عن خصائص وسلوك الفئة .
الآن إذا أردنا تحويل هذه الأمثلة إلى أكواد، يمكننا تخيل المثال التالي :
نعرف أن جميع الكائنات الحيه ( إذا أردنا أن نطلق عليها حيه ) يجب أن تتغذى وتتنفس (على سبيل المثال)، فسنتخيل هذا السلوك عبارة عن واجهة يمكن تطبيقها على جميع الكائنات الحية ، فالإنسان والحيوان والنبات والطير وغيرها تتغذى وتتنفس . لكن لا يمكن أن نطلق على كائن حي صفة الحياه إن كان لا يأكل ولا يتنفس. لاحظ الكود التالي:
<?php interface livecreature{ public function feed(); public function breath(); } class human implements livecreature { public function feed(){ return "I am a live creature and i eat fresh and cocked foods"; } public function breath(){ return "I am a live creature and i breath"; } } class animal implements livecreature { public function feed(){ return "I am a live creature and i eat none fresh and none cocked foods"; } public function breath(){ return "I am a live creature and i breath"; } } class plant implements livecreature { public function feed(){ return "I am a live creature and i feed on water"; } public function breath(){ return "I am a live creature and i breath"; } } /*class bird implements livecreature { public function breath(){ return "I am a live creature and i breath"; } }*/ $human = new human(); echo $human->feed().'<br>'; echo $human->breath(); ?>شرح الكود :
1 – قمنا السطر رقم 2 بتعريف الواجهة ()livecreature تضم السلوك المشترك لكل الكائنات باستخدام الكلمة interface.
2 – ثم في السطر رقم 6 قمنا بتطبيق الواجهة على فئة الإنسان باستخدام الكلمة implements مع إعادة تعريف الطرق المجرده التي تم تعريفها في الواجهة.
3 – ثم كررنا نفس الشيئ مع فئة الحيوان في السطر رقم 14 والنبات في السطر رقم 22 .
4- لكن ف السطر رقم 30 قمنا بتطبيق الواجهة على الطير ولكن لم نقم بإضافة كل الطرق التي تم تعريفها داخل الواجهة ( أي لم نقم بتطبيق بنود العقد كاملة ) , لذلك لايمكن أن يكون الطائر كائن حي. وبهذا عند إزالة علامة التعليق /*…*/ ( PHP Comments ) سيظهر خطأ ينص على أنه يجب إضافة الطريقة الأخرى التي لم يتم إضافتها. ( قم بإزالة علامة التعليق حتى ترى الخطأ )
[highlight background=”” color=””]قد لا يظهر الخطأ وقد يتم تسجيله في ملف Error_log وذلك حسب إعدادات معالجة الأخطاء PHP Error Handling[/highlight]
[button title=”عرض نتيجة / تحميل الكود” link=”https://makiomar.com/php-oop/interfaces/php_interface.php” target=”_blank” size=”” color=”” class=””]
توريث الواجهات Interfaces Inheritanceيمكن توريث الواجهات أيضاً باستخدام الكلمة extends ولا يجب إعادة تعريف الطرق التي تم تعريفها في الفئة الموروثة مرة أخرى داخل الفئة الوارثة
interface template1{ public function f1(); } interface template2 extends template1{ public function f2(); }وعند تطبيق الواجهة الوارثة ( template2 ) على فئة ما ، يجب عليك استخدام كل الطرق التي تم تعريفها داخل كلا من الواجهة الوارثة والموروثة ، أعني بهذا ( template2, template1 ) هكذا
interface template1{ public function f1(); } interface template2 extends template1{ public function f2(); } class abc implements template2{ public function f1(){ //Your function body } public function f2(){ //your function body } } التوريث المتعدد للواجهاتيمكن لواجهة أن ترث أكثر من واجهة هكذا
interface template1{ public function f1(); } interface template2{ public function f2(); } interface template3 extends template1, template2{ public function f3(); } تطبيق الواجهاتعند تطبيق واجهة A على فئة ما، يجب استخدام الطرق التي تم تعريفها في الواجهة A داخل الفئة بنفس الشكل وعدد الوسائط ( Function Arguments )
//هذا كود سليم interface template1{ public function f1($a) } class test implements template1{ public function f1($a) { echo $a; } } //هذا كود غير سليم interface template1{ public function f1($a) } class test implements template1{ public function f1($a) { echo $a; } }[highlight background=”” color=””]لايشترط أن تستخدم نفس اسم الوسيط ، وإذا قمت بتخصيص قيمة افتراضية له، فيمكنك أيضاً تغيير هذه القيمة[/highlight]
التطبيق المتعدد للواجهاتيمكن تطبيق أكثر من واجهة على فئة واحدة هكذا
interface template1{ public function f1(); } interface template2{ public function f2(); } class test implments template1, template2{ public function f1(){ //your function body } public function f2(){ //your function body } }[highlight background=”” color=””]لا يمكن تطبيق واجهتان بهما طريقتان يحملان نفس الاسم [/highlight]
الفرق بين الواجهات Interfaces والفئات المجرده Abstract Classes يتم تعريف الواجهات باستخدام الكلمة interface ، أما الفئات المجردة يتم تعريفها باستخدام الكلمة Abstract يتم تعريف طرق مجرده داخل الواجهه ولكن بدون استخدام الكلمة abstract ، على عكس الفئات المجرده يجب استخدام الكلمة Abstract يجب أن تكون حدود الرؤية ( PHP Visibility ) عامة public فقط، بينما الفئات المجرده يمكن أن تكون عامة أو محمية protected الفئات المجرده يمكن أن تحتوي على ثوابت ، طرق كاملة ، طرق مجرده ( method stubs ) ، بينما الواجهات يمكن أن تحتوي فقط على ثوابت وطرق مجرده. عند توريث الفئات المجرده ( PHP Inheritance ) ، عليك إعادة تعريف الطرق المجرده مرة أخرى داخل الفئة الوارثة ، على عكس الواجهات فعلا يتم إعادة تعريف الطرق المجرده عندما ترث الواجهات بعضها البعض. فأنت تقوم بإعادة التعريف بالأساس لإضافة كود قابل للتنفيذ بينما الواجهات يتم تعريف طرق مجرده فقط داخلها. يمكن لفئة ما وراثة فئة واحده أخرى وليس أكثر بينما يمكن للواجهه أن ترث أكثر من واجهة. ويمكن أن يتم تطبيق أكثر من واجهة على فئه واحده. عند توريث الفئات المجرده, يتم إعادة تعريف الطرق المجرده بحدود رؤيه أقل منعاً أو نفس التي تم تعريفها في الفئة الموروثة. بينما عند تطبيق واجهة على فئة ما يجب استخدام نفس حدود الرؤية للطريقة المجرده التي تم استخدامها في الواجهة نفسها وهي public . متى تستخدم الواجهات إذا كنت متأكد أن جميع الطرق ستكون مجرده في سلسلة توريث لفئات لها علاقة ببعض قم باستخدام الفئات المجرده أما إذا كانت غير مرتبطة ببعض يتم استخدام الواجهات. إذا كنت تريد تحديد سلوك ما لنوع من البيانات ولكن غير مهتم بالطريقة التي سيتم تنفيذا هذا السلوك بها عليك استخدام الواجهات. ( مثلاً : كلاً من الانسان والحيوان يأكلان لكن كل مهم له طريقته في الأكل) إذا كنت تريد استخدام التوريث المتعدد. تعرف أن حدود الرؤية المستخدمة في الواجهات هي public فقط ، فإذا أردت غير ذلك عليك باستخدام الفئات المجرده. إذا كنت تريد تعريف عناصر غير ساكنة ( Static ) أو غير نهائية ( Final ).

