5. الكائنات
5.1. يمكن لأي متغير أن يصبح كائنًا له سمات (مثال_14)
<?php
// any variable can have attributes by construction
$obj1->attr1 = "un";
$obj1->attr2 = 100;
// displays the
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
// modify object
$obj1->attr2+=100;
// displays the
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
// assigns the value of object1 to object2
$obj2 = $obj1;
// modify obj2
$obj2->attr2 = 0;
// displays both objects
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
print "objet2=[$obj2->attr1,$obj2->attr2]\n";
// assigns the reference from object1 to object3
$obj3 = &$obj1;
// modify obj3
$obj3->attr2 = 10;
// displays both objects
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
print "objet3=[$obj3->attr1,$obj3->attr2]\n";
// is an object a dictionary?
print count($obj1)."\n";
while (list($attribut, $valeur) = each($obj1))
print "obj1[$attribut]=$valeur\n";
// end
exit;
?>
النتائج:
objet1=[un,100]
objet1=[un,200]
objet1=[un,0]
objet2=[un,0]
objet1=[un,10]
objet3=[un,10]
1
obj1[attr1]=un
obj1[attr2]=10
تعليقات
- السطر 4: تشير الصيغة $obj->attr إلى السمة attr للمتغير $obj. إذا لم تكن موجودة، يتم إنشاؤها، مما يجعل المتغير $obj كائنًا له سمات.
- السطر 13: التعبير $obj2 = $obj1، عندما يكون $obj1 كائنًا، يمثل نسخًا للكائنات عن طريق الإشارة. وبالتالي، فإن $obj2 و$obj1 هما إشارتان إلى الكائن نفسه. ويمكن تعديل الكائن نفسه من خلال أي من الإشارتين.
- السطر 20: يعين التعبير $obj3=&$obj1 مرجع (عنوان) المتغير $obj1 إلى $obj3. إذا كان $obj1 كائنًا، كما هو الحال هنا، فإن التعبير السابق يعادل $obj3=$obj1.
- السطران 28-29: يوضحان أنه يمكن تصفح الكائن مثل القاموس. مفاتيح القاموس هي أسماء السمات، وقيم القاموس هي قيم تلك السمات نفسها.
- السطر 27: يمكن تطبيق دالة count على كائن ولكنها لا تُرجع، كما قد يتوقع المرء، عدد السمات. لذلك، يشترك الكائن في أوجه تشابه مع القاموس ولكنه ليس قاموسًا.
5.2. فئة Person بدون سمات مُعلنة (example_15)
<?php
class Personne {
// class attributes
// undeclared - can be created dynamically
// method
function identité() {
// a priori, uses non-existent attributes
return "[$this->prénom,$this->nom,$this->âge]";
}
}
// test
// attributes are public and can be created dynamically
$p = new Personne();
$p->prénom = "Paul";
$p->nom = "Langevin";
$p->âge = 48;
// method call
print "personne=" . $p->identité() . "\n";
// end
exit;
?>
النتائج:
تعليقات
- الأسطر 3–13: تعريف فئة Person. الفئة هي نموذج يُستخدم لإنشاء كائنات. وتُعد الفئة مجموعة من السمات والوظائف التي تُسمى «الأساليب». ولا يلزم إعلان السمات.
- الأسطر 9–12: تعرض الطريقة identity قيم ثلاث سمات لم يتم الإعلان عنها في الفئة. تشير الكلمة الرئيسية $this إلى الكائن الذي تُطبق عليه الطريقة.
- السطر 17: يتم إنشاء كائن $p من النوع Person. تُستخدم الكلمة الرئيسية new لإنشاء كائن جديد. تُرجع العملية مرجعًا إلى الكائن الذي تم إنشاؤه (أي عنوان). هناك عدة طرق لكتابة ذلك: new Person()، new Person، new person. لا يُفرق اسم الفئة بين الأحرف الكبيرة والصغيرة.
- الأسطر 18-20: يتم إنشاء السمات الثلاث المطلوبة بواسطة طريقة identity في الكائن $p.
- السطر 22: يتم تطبيق طريقة identity لفئة Person على الكائن $p. في كود (الأسطر 9–11) لطريقة identity، يشير $this إلى نفس الكائن الذي يشير إليه $p.
5.3. فئة Person مع السمات المعلنة (example_16)
<?php
class Personne {
// class attributes
var $prénom;
var $nom;
var $âge;
// method
function identité() {
return "[$this->prénom,$this->nom,$this->âge]";
}
}
// test
// attributes are public
$p = new Personne();
$p->prénom = "Paul";
$p->nom = "Langevin";
$p->âge = 48;
// method call
print "personne=" . $p->identité() . "\n";
// end
exit;
?>
النتائج:
تعليقات
5.4. فئة Person مع منشئ (example_17)
أظهرت الأمثلة السابقة فئات Person غريبة كما كانت موجودة في PHP 4. لا يُنصح باتباع هذه الأمثلة. نقدم الآن فئة Person تتبع أفضل ممارسات PHP 5:
<?php
class Personne {
// class attributes
private $prénom;
private $nom;
private $âge;
// getters and setters
public function getPrénom() {
return $this->prénom;
}
public function getNom() {
return $this->nom;
}
public function getAge() {
return $this->âge;
}
public function setPrénom($prénom) {
$this->prénom = $prénom;
}
public function setNom($nom) {
$this->nom = $nom;
}
public function setAge($age) {
$this->âge = $age;
}
// manufacturer
function __construct($prénom, $nom, $âge) {
// we go through sets
$this->setPrénom($prénom);
$this->setNom($nom);
$this->setAge($âge);
}
// method toString
function __toString() {
return "[$this->prénom,$this->nom,$this->âge]";
}
}
// test
// creation of a person object
$p = new Personne("Paul", "Langevin", 48);
// identity of this person
print "personne=$p\n";
// we change the age
$p->setAge(14);
// identity of the person
print "personne=$p\n";
// end
exit;
?>
النتائج:
تعليقات
- السطور 3-48: فئة Person
- الأسطر 6-8: السمات الخاصة بالفئة. هذه السمات مرئية فقط داخل الفئة. الكلمات الرئيسية الأخرى التي يمكن استخدامها هي:
- public: تجعل السمة سمة عامة مرئية من خارج الفئة
- protected: تجعل السمة سمة محمية يمكن رؤيتها من داخل الفئة والفئات المشتقة منها.
- نظرًا لأن السمات خاصة، فلا يمكن الوصول إليها من خارج الفئة. لذلك، لا يمكننا كتابة الكود التالي:
هنا، نحن خارج فئة Person. وبما أن السمة name خاصة، فإن السطر 2 غير صحيح. لتهيئة الحقول الخاصة للكائن $p، هناك طريقتان:
- (تابع)
- استخدام طرق set و get العامة (يمكن أن تكون أسماء هذه الطرق أي شيء) من الأسطر 11–33. يمكننا بعد ذلك كتابة:
- (تابع)
- استخدم المنشئ من الأسطر 36–41. عندئذ سنكتب:
يستدعي الكود أعلاه تلقائيًا طريقة فئة Person المسماة __construct.
- السطر 54: يعرض هذا السطر Person $p كسلسلة. للقيام بذلك، يتم استخدام طريقة فئة Person المسماة __toString.
5.5. فئة Person مع فحوصات الصحة في المنشئ (example_18)
يعد منشئ الفئة المكان المناسب للتحقق من صحة قيم تهيئة الكائن. ومع ذلك، يمكن أيضًا تهيئة الكائن عبر طرق set الخاصة به أو ما يعادلها. لتجنب تكرار نفس الفحوصات في مكانين مختلفين، سنضعها داخل طرق set. إذا تبين أن قيمة تهيئة الكائن غير صحيحة، فسيتم إصدار استثناء. فيما يلي مثال على ذلك:
<?php
class Personne {
// class attributes
private $prénom;
private $nom;
private $âge;
// getters and setters
public function getPrénom() {
return $this->prénom;
}
public function getNom() {
return $this->nom;
}
public function getAge() {
return $this->âge;
}
public function setPrénom($prénom) {
// first name must be non-empty
if (!preg_match("/^\s*(.+?)\s*$/", $prénom, $champs)) {
throw new Exception("Le prénom doit être non vide");
} else {
$this->prénom = $champs[1];
}
}
public function setNom($nom) {
// name must be non-empty
if (!preg_match("/^\s*(.+?)\s*$/", $nom, $champs)) {
throw new Exception("Le nom doit être non vide");
} else {
$this->nom = $champs[1];
}
}
public function setAge($âge) {
// age must be valid
if (!preg_match("/^\s*(\d+)\s*$/", $âge, $champs)) {
throw new Exception("L'âge doit être un entier positif ou nul");
} else {
$this->âge = $champs[1];
}
}
// manufacturer
function __construct($prénom, $nom, $âge) {
// we go through sets
$this->setPrénom($prénom);
$this->setNom($nom);
$this->setAge($âge);
}
// method toString
function __toString() {
return "[$this->prénom,$this->nom,$this->âge]";
}
}
// test
// creation of a Personne object
$p = new Personne("Paul", "Langevin", 48);
// identity of this person
print "personne=$p\n";
// creation of an erroneous Person object
try {
$p = new Personne("xx", "yy", "zz");
} catch (Exception $e) {
print $e->getMessage();
}
// end
exit;
?>
النتائج:
تعليقات
- الأسطر 23-30: تهيئة السمة first_name والتحقق من قيمة التهيئة
- السطر 25: استخدام تعبير عادي. الاسم الأول هو تسلسل من حرف واحد أو أكثر، قد يتبعه أو يسبقه مسافات.
- السطر 26: إذا كان الاسم الأخير فارغًا، يتم إلقاء استثناء؛ وإلا، يتم تخزين الاسم الأول (السطر 28)
- السطر 66: استخدام منشئ فئة Person
- السطر 68: استخدام طريقة __toString لفئة Person
- الأسطر 70-74: معالجة أي استثناء يتم إلقائه بواسطة منشئ فئة Person.
5.6. إضافة طريقة تعمل كمنشئ ثانٍ (مثال_19)
في PHP 5، لا يمكن وجود عدة منشئات بمعلمات مختلفة تسمح بإنشاء كائن بطرق متنوعة. لذلك يمكننا استخدام طرق تعمل كمنشئات:
<?php
class Personne {
// class attributes
private $prénom;
private $nom;
private $âge;
// getters and setters
public function getPrénom() {
return $this->prénom;
}
….
// manufacturer
function __construct($prénom, $nom, $âge) {
// we go through sets
$this->setPrénom($prénom);
$this->setNom($nom);
$this->setAge($âge);
}
// method
public function initWithPersonne($p) {
// initializes the current object with a person $p
$this->__construct($p->prénom, $p->nom, $p->âge);
}
// method toString
function __toString() {
return "[$this->prénom,$this->nom,$this->âge]";
}
}
// test
// creation of a Personne object
$p = new Personne("Paul", "Langevin", 48);
// identity of this person
print "personne=$p\n";
// creation of a second person
$p2 = new Personne("Laure", "Adeline", 67);
// initialization of the first with the values of the second
$p->initWithPersonne($p2);
// check
print "personne=$p\n";
// end
exit;
?>
النتائج:
تعليقات
- الأسطر 26-29: تسمح لك طريقة initWithPerson بتعيين قيم سمات كائن Person آخر إلى الكائن الحالي. هنا، تستدعي المنشئ __construct، ولكن هذا ليس إلزامياً.
5.7. مصفوفة من كائنات Person (example_20)
يوضح المثال التالي أنه يمكنك إنشاء مصفوفات من الكائنات.
<?php
class Personne {
// class attributes
private $prénom;
private $nom;
private $âge;
// getters and setters
public function getPrénom() {
return $this->prénom;
}
...
// manufacturer
function __construct($prénom, $nom, $âge) {
// we go through sets
$this->setPrénom($prénom);
$this->setNom($nom);
$this->setAge($âge);
}
// method
public function initWithPersonne($p) {
….
}
// method toString
function __toString() {
...
}
}
// test
// create an array of Personne objects
$groupe = array(new Personne("Paul", "Langevin", 48), new Personne("Sylvie", "Lefur", 70));
// identity of these persons
for ($i = 0; $i < count($groupe); $i++)
print "groupe[$i]=$groupe[$i]\n";
// end
exit;
?>
النتائج:
تعليقات
- السطر 39: إنشاء مصفوفة من شخصين
- السطر 42: تكرار المصفوفة
- السطر 43: $group[$i] هو كائن من نوع Person. تُستخدم طريقة __toString لعرضه.
5.8. إنشاء فئة مشتقة من فئة Person (example_21)
<?php
class Personne {
// class attributes
private $prénom;
private $nom;
private $âge;
// getters and setters
public function getPrénom() {
return $this->prénom;
}
...
// manufacturer
function __construct($prénom, $nom, $âge) {
// we go through sets
$this->setPrénom($prénom);
$this->setNom($nom);
$this->setAge($âge);
}
// method
public function initWithPersonne($p) {
// initializes the current object with a person $p
$this->__construct($p->prénom, $p->nom, $p->âge);
}
// method toString
function __toString() {
return "[$this->prénom,$this->nom,$this->âge]";
}
}
// a class derived from Personne
class Enseignant extends Personne {
// attributes
private $discipline; // d// subject taught
// getter and setter
public function getDiscipline() {
return $this->discipline;
}
public function setDiscipline($discipline) {
$this->discipline = $discipline;
}
// manufacturer
public function __construct($prénom, $nom, $âge, $discipline) {
// parent attributes
parent::__construct($prénom, $nom, $âge);
// other attributes
$this->setDiscipline($discipline);
}
// overloads the __toString function of the parent class
public function __toString() {
return "[" . parent::__toString() . ",$this->discipline]";
}
}
// test
// creation of an array of Personne and derived objects
$groupe = array(new Enseignant("Paul", "Langevin", 48, "anglais"), new Personne("Sylvie", "Lefur", 70));
// identity of these persons
for ($i = 0; $i < count($groupe); $i++)
print "groupe[$i]=$groupe[$i]\n";
// end
exit;
?>
النتائج:
تعليقات
- الأسطر 3-35: فئة Person
- السطر 38: فئة Teacher تمتد من فئة Person. فئة Teacher المشتقة ترث سمات وأساليب فئتها الأم.
- السطر 41: تضيف فئة Teacher سمة جديدة، وهي subject، وهي سمة خاصة بها
- السطر 55: يأخذ منشئ فئة Teacher 4 معلمات
- 3 لتهيئة فئتها الأم (first_name، last_name، age)
- 1 لتهيئة نفسها (subject)
- السطر 57: الفئة المشتقة لديها حق الوصول إلى طرق ومنشئات فئتها الأصلية عبر الكلمة الرئيسية parent::. هنا، نمرر المعلمات (first_name، last_name، age) إلى منشئ الفئة الأصلية.
- السطر 64: تستخدم طريقة __toString للفئة المشتقة طريقة __toString للفئة الأصلية.
- السطر 71: مصفوفة تحتوي على كائن Teacher وكائن Person.
- السطر 74: نقوم بتكرار عناصر المصفوفة
- السطر 75: سيتم استدعاء طريقة __toString لكل عنصر من عناصر $group[$i]. تحتوي فئة Person على طريقة __toString. أما فئة Teacher فتحتوي على طريقتين: طريقة الفئة الأم وطريقتها الخاصة. قد يتساءل المرء أيهما سيتم استدعاؤه. يظهر التنفيذ أن الطريقة التي تم استدعاؤها هي طريقة فئة Teacher. وهذا هو الحال دائمًا: عندما يتم استدعاء طريقة على كائن، يتم البحث عنها بالترتيب التالي: في الكائن نفسه، ثم في فئته الأصلية إن وجدت، ثم في الفئة الأصلية للفئة الأصلية، وهكذا دواليك... ويتوقف البحث بمجرد العثور على الطريقة.
5.9. إنشاء فئة ثانية مشتقة من فئة Person (example_22)
يُنشئ المثال التالي فئة Student مشتقة من فئة Person:
<?php
class Personne {
// class attributes
private $prénom;
private $nom;
private $âge;
// getters and setters
public function getPrénom() {
return $this->prénom;
}
...
// manufacturer
function __construct($prénom, $nom, $âge) {
// we go through sets
$this->setPrénom($prénom);
$this->setNom($nom);
$this->setAge($âge);
}
// method
public function initWithPersonne($p) {
// initializes the current object with a person $p
...
}
// method toString
function __toString() {
return "[$this->prénom,$this->nom,$this->âge]";
}
}
// a class derived from personne
class Enseignant extends Personne {
// attributes
private $discipline; // d// subject taught
// getter and setter
...
// manufacturer
public function __construct($prénom, $nom, $âge, $discipline) {
// parent attributes
parent::__construct($prénom, $nom, $âge);
// other attributes
$this->setDiscipline($discipline);
}
// overloads the _identité__toString function of the parent class
public function __toString() {
return "[" . parent::__toString() . ",$this->discipline]";
}
}
// a class derived from Personne
class Etudiant extends Personne {
// attributes
private $formation; // d// subject taught
// getter and setter
public function getFormation() {
return $this->formation;
}
public function setFormation($formation) {
$this->formation = $formation;
}
// manufacturer
public function __construct($prénom, $nom, $âge, $formation) {
// parent attributes
parent::__construct($prénom, $nom, $âge);
// other attributes
$this->setFormation($formation);
}
// overloads the __toString function of the parent class
public function __toString() {
return "[" . parent::__toString() . ",$this->formation]";
}
}
// test
// creation of a table of person objects and derivatives
$groupe = array(new Enseignant("Paul", "Langevin", 48, "anglais"), new Personne("Sylvie", "Lefur", 70), new Etudiant("Steve", "Boer", 23, "iup2 qualité"));
// identity of these persons
for ($i = 0; $i < count($groupe); $i++)
print "groupe[$i]=$groupe[$i]\n";
// end
exit;
?>
النتائج:
groupe[0]=[[Paul,Langevin,48],anglais]
groupe[1]=[Sylvie,Lefur,70]
groupe[2]=[[Steve,Boer,23],iup2 qualité]
5.10. الواجهات (مثال_23)
الواجهة هي بنية تحدد نماذج أولية للطرق. وتحدد الفئة التي تنفذ واجهة ما كود جميع طرق تلك الواجهة.
<?php
// an interface
interface IExemple {
function ajouter($i, $j);
function soustraire($i, $j);
}
// interface implementation 1
class Classe1 implements IExemple {
public function ajouter($a, $b) {
return $a + $b + 10;
}
public function soustraire($a, $b) {
return $a - $b + 20;
}
}
// interface implementation 2
class Classe2 implements IExemple {
public function ajouter($a, $b) {
return $a + $b + 100;
}
public function soustraire($a, $b) {
return $a - $b + 200;
}
}
// function
function calculer($a, $b, IExemple $interface) {
print $interface->ajouter($a, $b)."\n";
print $interface->soustraire($a, $b)."\n";
}
// ------------------- hand
// creation of 2 objects of type Class1 and Class2
$c1 = new Classe1();
$c2 = new Classe2();
// call the calculate function
calculer(4, 3, $c1);
calculer(14, 13, $c2);
?>
النتائج
تعليقات
- الأسطر 4–8: تحدد واجهة IExample طريقتين: دالة add (السطر 5) ودالة subtract (السطر 7). لا تحدد الواجهة الكود الخاص بهاتين الطريقتين. ستقوم الفئات التي تنفذ الواجهة بذلك.
- السطر 11: تنفذ الفئة Class1 واجهة IExample. وبالتالي، فإنها تحدد كودًا لطريقة add (السطر 13) وطريقة subtract (السطر 17).
- الأسطر 24–34: ينطبق الأمر نفسه على فئة Class2.
- السطر 37: تأخذ طريقة
*calculerثلاثة معلمات: عددين صحيحين،*$a*و$b*، وكائن*$interfaceالذي ينفذ واجهة*IExemple. كان بإمكاننا كتابةfunction calculate($a, $b, $interface)دون تحديد نوعIExampleللمعلمة*$interface*. وبتحديد ذلك، نسمح لمترجم PHP بالتحقق من أن المعلمة الفعلية هي بالفعل كائن ينفذ واجهة*IExample*. - السطران 38-39: استخدام طريقتي add و subtract في كائن $interface. ونظرًا لأنه يُنفِّذ واجهة IExample، فإننا نعلم أنه يحتوي على هاتين الطريقتين.
- السطران 44-45: إنشاء كائنين من أنواع مختلفة، وكلاهما ينفذ واجهة IExample.
- السطر 47: نمرر الكائن $c1 من النوع Class1، الذي ينفذ واجهة IExample، إلى الدالة calculate.
- السطر 48: يتم تمرير الكائن $c2 من النوع Class2، الذي ينفذ واجهة IExample، إلى الدالة calculate.