Skip to content

6. الواجهات

الواجهة هي بنية تحدد نماذج أولية للطرق. يجب على الفئة التي تنفذ واجهة أن تحدد كود جميع طرق الواجهة.

6.1. هيكل الشجرة للنصوص البرمجية

Image

6.2. واجهة أولى

نحدد واجهة [IExemple] في نص برمجي [IExemple.php]. في هذا النص البرمجي نفسه، نحدد فئتين تنفذان الواجهة [IExemple]:


<?php

// الالتزام الصارم بأنواع معلمات الدوال
declare(strict_types=1);

// مساحة الأسماء
namespace Exemples;

// واجهة
interface IExemple {
    // طرق الواجهة
    public function ajouter(int $i, int $j): int;
    public function soustraire(int $i, int $j): int;
}

// التنفيذ 1 للواجهة IExemple
class Classe1 implements IExemple {
    public function ajouter(int $a, int $b): int {
        return $a + $b + 10;
    }

    public function soustraire(int $a, int $b): int {
        return $a - $b + 20;
    }

}

// التنفيذ 2 للواجهة IExemple
class Classe2 implements IExemple {
    public function ajouter(int $a, int $b) : int{
        return $a + $b + 100;
    }

    public function soustraire(int $a, int $b) : int {
        return $a - $b + 200;
    }

}

تعليقات

  • الأسطر 10-14: تحدد الواجهة IExemple طريقتين: الدالة ajouter (السطر 12) والدالة soustraire (السطر 13). لا تحدد الواجهة كود هذه الطرق. بل ستقوم بذلك الفئات التي تنفذ الواجهة؛
  • السطر 17: الفئة Classe1 تنفذ (تطبق) الواجهة IExemple. وبالتالي، فإنها تحدد كودًا للطريقتين ajouter (السطر 18) و soustraire (السطر 22)؛
  • الأسطر 29-38: الأمر نفسه بالنسبة للفئة Classe2؛

نستخدم واجهة [IExemple] في البرنامج النصي [interfaces-01.php] التالي:


<?php

require_once "IExemple.php";
use \Exemples\Classe1;
use \Exemples\Classe2;
use \Exemples\IExemple;

// وظيفة
function calculer(int $a, int $b, IExemple $interface) : void {
  print $interface->ajouter($a, $b)."\n";
  print $interface->soustraire($a, $b)."\n";
}

// ------------------- main
// إنشاء كائنين من النوع Classe1 و Classe2
$c1 = new Classe1();
$c2 = new Classe2();
// استدعاء الدالة calculate
calculer(4, 3, $c1);
calculer(14, 13, $c2);

تعليقات

  • الأسطر 3-6: تضمين وتعريف الفئات والواجهات المستخدمة في البرنامج النصي؛
  • السطر 3: بدلاً من الأمر include، استخدمنا هنا الأمر require_once. تقوم تعليمة include بتضمين ملف في البرنامج النصي الحالي حتى لو كان قد تم تضمينه مسبقًا، في حين أن تعليمة require_once لا تضمّنه إلا مرة واحدة. لذا، فيما يتعلق بتضمين الكود، نفضل استخدام تعليمة require_once؛
  • الأسطر 9-12: نُعرِّف دالة؛
  • السطر 9: قمنا هنا بتعريف نوع المعلمات الثلاثة. إذا لم يكن المعلم الفعلي عند التنفيذ من النوع المتوقع، يتم إصدار خطأ. المعلم الثالث من النوع [IExemple]. وهذا يعني أن المعلمة الفعلية يجب أن تكون مثيلًا لفئة تُنفِّذ الواجهة [IExemple]، وبالتالي في مثالنا، مثيلًا لفئتي [Classe1] أو [Classe2]؛
  • السطران 10-11: نستخدم طرق [ajouter, soustraire] من واجهة [IExemple
  • السطر 19: المعلمة الفعلية الثالثة هي من النوع [Classe1] المتوافق مع النوع [IExemple] للمعلمة الشكلية الثالثة للدالة؛
  • السطر 20: الأمر نفسه بالنسبة للفئة [Classe2]؛

النتائج

1
2
3
4
17
21
127
201

6.3. اشتقاق واجهة

وكما يمكن لفئة فرعية أن ترث فئة أصلية، يمكن لواجهة فرعية أن ترث واجهة أصلية.

لنأخذ على سبيل المثال الواجهة [IExemple2] المُعرَّفة في الملف [IExemple2.php]:


<?php

// الالتزام الصارم بأنواع معلمات الدوال
declare(strict_types=1);
// مساحة الأسماء
namespace Exemples;

// تضمين تعريف الواجهة IExemple
require_once __DIR__."/IExemple.php";

// واجهة مشتقة من IExemple
interface IExemple2 extends IExemple {
    // طريقة الواجهة
    public function multiplier(int $i, int $j): int;
}

// تنفيذ واجهة IExemple2
class Classe3 extends Classe2 implements IExemple2 {
   
    public function multiplier(int $a, int $b): int {
        return $a * $b;
    }

}

تعليقات

  • السطر 6: ستكون الواجهة [IExemple2] في نفس مساحة الأسماء مثل الواجهة [Iexemple]؛
  • السطر 9: يتم تضمين ملف تعريف الواجهة [Iexemple]؛
  • الأسطر 12-15: تُعرّف الواجهة [IExemple2] التي تمتد (ترث) من الواجهة [Iexemple] وتضيف إليها طريقة جديدة (السطر 14)؛
  • الأسطر 18-24: الفئة [Classe3] تمتد من الفئة [Classe2]. وبما أن هذه الأخيرة تُنفِّذ الواجهة [IExemple]، فسيكون الأمر كذلك بالنسبة للفئة [Classe3]. ففي الواقع، ترث [Classe3] جميع الطرق العامة والمحمية للفئة [Classe2]، ومن ثم ترث طريقتي «الإضافة» و«الطرح». من ناحية أخرى، يُشار إلى أن [Classe3] تُنفذ واجهة [IExemple2]. وبهذا الصفة، يجب عليها أيضًا تنفيذ طريقة الضرب، وهو ما لا تفعله [Classe2]. وهذا ما تفعله الأسطر 20-22؛

يتم استخدام الواجهة [IExemple2] بواسطة البرنامج النصي [interfaces-02] التالي:


<?php

// الالتزام الصارم بأنواع معلمات الدوال
declare(strict_types=1);

// تضمين وتحديد الفئات والواجهات اللازمة للنص البرمجي
require_once __DIR__."/Iexemple2.php";
use \Exemples\IExemple2;
use \Exemples\Classe3;

// الدالة
function calculer(int $a, int $b, IExemple2 $interface) {
    print $interface->ajouter($a, $b) . "\n";
    print $interface->soustraire($a, $b) . "\n";
    print $interface->multiplier($a, $b) . "\n";
}

// ------------------- main
// إنشاء كائن واحد من نوع «Classe3» الذي ينفذ IExemple2
$c3 = new Classe3();
// استدعاء الدالة «calculer»
calculer(4, 3, $c3);

تعليقات

  • السطر 12: المعلمة الثالثة للدالة [calculer] هي من النوع [IExemple2
  • الأسطر 13-15: يتم استخدام الطرق الثلاث لواجهة [IExemple2]؛
  • السطر 22: يتم استدعاء الدالة [calculer] مع المعلمة الثالثة ككائن من النوع [IExemple2] (السطر 20)؛

النتائج

1
2
3
107
201
12

6.4. تمرير واجهة كمعلمة لدالة

لقد رأينا في الفقرة السابقة أنه عندما يكون النوع المتوقع لمعلمة الدالة هو فئة، فإن المعلمة الفعلية يمكن أن تكون كائنًا من النوع المتوقع أو مشتقًا منه. وينطبق الأمر نفسه على الواجهات كما يوضح البرنامج النصي التالي [interfaces-03.php]:


<?php

// الالتزام الصارم بأنواع معلمات الدوال
declare(strict_types=1);

// تضمين وتحديد الفئات والواجهات اللازمة للنص البرمجي
require_once __DIR__."/IExemple.php";
use \Exemples\IExemple;
require_once __DIR__."/IExemple2.php";
use \Exemples\Classe3;

// الدالة
function calculer(int $a, int $b, IExemple $interface) {
  print $interface->ajouter($a, $b) . "\n";
  print $interface->soustraire($a, $b) . "\n";
}

// ------------------- main
// إنشاء كائن واحد من نوع Classe3 الذي ينفذ IExemple2 وبالتالي IExemple
$c3 = new Classe3();
// استدعاء الدالة «calculer»
calculer(4, 3, $c3);

تعليقات

  • السطر 13: تتوقع الدالة [calculer] كمعلمة ثالثة نوعًا من النوع [IExemple]. وهذا يعني أن نوع المعلمة الفعلية يمكن أن يكون من النوع [IExemple] أو مشتقًا منه؛
  • السطر 20: يتم إنشاء مثيل لكائن $c3 من النوع [Classe3]، وهي فئة تُنفذ الواجهة [IExemple2] التي تمتد بدورها إلى الواجهة [IExemple]. وبالتالي، فإن $c3 تُنفِّذ في النهاية الواجهة [IExemple]؛
  • السطر 22: يتم استدعاء الدالة [calculer] مع كائن $c3 من النوع [Classe3] كمعلمة ثالثة. من خلال آلية وراثة الفئات والتطبيقات، رأينا أن الكائن $c3 يطبق النوع [IExemple]. لذا يمكن استخدامه كمعلمة ثالثة؛

النتائج

107
201