3. أساسيات PHP
3.1. هيكل النصوص البرمجية

3.2. تكوين PHP
يأتي PHP مهيئًا مسبقًا بواسطة ملف نصي [php.ini]. يمكن تغيير جميع هذه الإعدادات برمجيًا. تؤثر إعدادات PHP بشكل كبير على تنفيذ البرامج النصية. لذا من المهم معرفتها. يسمح البرنامج النصي التالي [phpinfo.php] بذلك:
تعليقات
- السطر 3: تعرض الدالة [phpinfo] إعدادات PHP؛
نتائج التنفيذ
تعرض الدالة [phpinfo] هنا أكثر من 800 سطر من التكوين. لن نعلق عليها لأن معظمها يتعلق بالاستخدام المتقدم لـ PHP. أحد الأسطر المهمة هو السطر 13 أعلاه: فهو يشير إلى الملف [php.ini] الذي تم استخدامه لتكوين الملف PHP الذي ستستخدمه لتنفيذ البرامج النصية الخاصة بك. إذا كنت ترغب في تعديل إعدادات تشغيل PHP، فهذا هو الملف الذي يجب عليك تعديله. يوجد العديد من التعليقات في هذا الملف لشرح دور الإعدادات المختلفة.
3.3. مثال أول
3.3.1. الكود
فيما يلي، نجد برنامج [bases-01.php] الذي يعرض الخصائص الأولى لبرنامج PHP.
<?php
// هذا تعليق
// متغير مستخدم دون أن يتم إعلانه
$nom = "dupont";
// عرض على الشاشة
print "nom=$nom\n";
// جدول يحتوي على عناصر من أنواع مختلفة
$tableau = array("un", "deux", 3, 4);
// عدد عناصره
$n = count($tableau);
// حلقة
for ($i = 0; $i < $n; $i++) {
print "tableau[$i]=$tableau[$i]\n";
}
// تهيئة متغيرين بمحتوى مصفوفة
list($chaine1, $chaine2) = array("chaine1", "chaine2");
// تسلسل السلسلتين
$chaine3 = $chaine1 . $chaine2;
// عرض النتيجة
print "[$chaine1,$chaine2,$chaine3]\n";
// استخدام دالة
affiche($chaine1);
// يمكن معرفة نوع المتغير
afficheType("n", $n);
afficheType("chaine1", $chaine1);
afficheType("tableau", $tableau);
// يمكن أن يتغير نوع المتغير أثناء التنفيذ
$n = "a changé";
afficheType("n", $n);
// يمكن للدالة أن تُرجع نتيجة
$res1 = f1(4);
print "res1=$res1\n";
// يمكن للدالة أن تُرجع مصفوفة من القيم
list($res1, $res2, $res3) = f2();
print "(res1,res2,res3)=[$res1,$res2,$res3]\n";
// كان من الممكن استرداد هذه القيم في مصفوفة
$t = f2();
for ($i = 0; $i < count($t); $i++) {
print "t[$i]=$t[$i]\n";
}
// اختبارات
for ($i = 0; $i < count($t); $i++) {
// لا يعرض سوى السلاسل
if (getType($t[$i]) === "string") {
print "t[$i]=$t[$i]\n";
}
}
// عوامل المقارنة == و ===
if("2"==2){
print "avec l'opérateur ==, la chaîne 2 est égale à l'entier 2\n";
}else{
print "avec l'opérateur ==, la chaîne 2 n'est pas égale à l'entier 2\n";
}
if("2"===2){
print "avec l'opérateur ===, la chaîne 2 est égale à l'entier 2\n";
}
else{
print "avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2\n";
}
// اختبارات أخرى
for ($i = 0; $i < count($t); $i++) {
// يعرض فقط الأعداد الصحيحة >10
if (getType($t[$i]) === "integer" and $t[$i] > 10) {
print "t[$i]=$t[$i]\n";
}
}
// حلقة while
$t = [8, 5, 0, -2, 3, 4];
$i = 0;
$somme = 0;
while ($i < count($t) and $t[$i] > 0) {
print "t[$i]=$t[$i]\n";
$somme += $t[$i]; //$somme=$somme+$t[$i]
$i++; //$i=$i+1
}//بينما
print "somme=$somme\n";
// نهاية البرنامج
exit;
//----------------------------------
function affiche($chaine) {
// يعرض $chaine
print "chaine=$chaine\n";
}
//يعرض
//----------------------------------
function afficheType($name, $variable) {
// يعرض نوع $variable
print "type[variable $" . $name . "]=" . getType($variable) . "\n";
}
//afficheType
//----------------------------------
function f1($param) {
// يضيف 10 إلى $param
return $param + 10;
}
//----------------------------------
function f2() {
// تُرجع 3 قيم
return array("un", 0, 100);
}
?>
النتائج:
nom=dupont
tableau[0]=un
tableau[1]=deux
tableau[2]=3
tableau[3]=4
[chaine1,chaine2,chaine1chaine2]
chaine=chaine1
type[variable $n]=integer
type[variable $chaine1]=string
type[variable $tableau]=array
type[variable $n]=string
res1=14
(res1,res2,res3)=[un,0,100]
t[0]=un
t[1]=0
t[2]=100
t[0]=un
avec l'opérateur ==, la chaîne 2 est égale à l'entier 2
avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2
t[2]=100
t[0]=8
t[1]=5
somme=13
تعليقات
- السطر 5: في PHP، لا يتم تحديد نوع المتغيرات. فهذه المتغيرات لها نوع ديناميكي يمكن أن يتغير بمرور الوقت. يمثل $nom المتغير الذي يحمل المعرف «nom»؛
- السطر 7: للكتابة على الشاشة، يمكن استخدام الأمر print أو الأمر echo؛
- السطر 9: تسمح الكلمة الرئيسية array بتعريف مصفوفة. المتغير $nom[$i] يمثل العنصر $i من المصفوفة $tableau؛
- السطر 11: تعرض الدالة count($tableau) عدد عناصر المصفوفة $tableau؛
- الأسطر 13-15: حلقة. ونظرًا لأن هذه الحلقة تحتوي على تعليمة واحدة فقط، فإن الأقواس المزدوجة اختيارية. وفي بقية هذا المستند، سنضع الأقواس المزدوجة بشكل منهجي بغض النظر عن عدد التعليمات؛
- السطر 14: تُحاط سلاسل الأحرف بعلامات اقتباس " أو علامات اقتباس مائلة '. داخل علامات الاقتباس، يتم تقييم المتغيرات $variable ولكن ليس داخل علامات الاقتباس المائلة؛
- السطر 17: تتيح الدالة list تجميع المتغيرات في قائمة وتعيين قيمة لها بعملية تعيين واحدة. هنا $chaine1="chaine1" و $chaine2="chaine2"؛
- السطر 19: العلامة . هي علامة ربط السلاسل؛
- الأسطر 83-86: الكلمة الرئيسية function تُعرّف دالة. قد تُرجع الدالة قيمًا أو لا تُرجعها من خلال التعليمات return. يمكن للكود المستدعي تجاهل نتائج الدالة أو استردادها. يمكن تعريف الدالة في أي مكان في الكود.
- السطر 92: تُرجع الدالة المُعرَّفة مسبقًا getType($variable) سلسلة أحرف تمثل نوع $variable. وقد يتغير هذا النوع بمرور الوقت؛
- السطر 45: يقوم عامل === بمقارنة عنصرين بشكل صارم: يجب أن يكونا من نفس النوع حتى يمكن مقارنتهما. أما عامل == فهو أقل صرامة: يمكن أن يكون عنصران متساويين دون أن يكونا من نفس النوع. وهذا ما توضحه التعليمات الواردة في الأسطر 50-60. في حالة عامل ==، تتم المقارنة بعد تحويل نوع العنصرين المقارنين إلى نفس النوع. وعندها تحدث تحويلات ضمنية. ومن السهل جدًّا «نسيان» وجود هذه التحويلات الضمنية، مما يؤدي إلى نتائج غير متوقعة، مثل اكتشاف أن شرطًا ما صحيح بينما كنت تتوقع أنه خطأ. لتجنب هذا المأزق، سنستخدم بشكل منهجي عامل المقارنة ===؛
- السطر 64: يمكن أيضًا استخدام عوامل التشغيل المنطقية or و!؛
- السطر 69: بدلاً من الترميز array()، يمكن استخدام الترميز [] لتهيئة مصفوفة من PHP7؛
- السطر 80: الدالة المُعرَّفة مسبقًا exit توقف تنفيذ البرنامج النصي؛
- السطر 107: تشير العلامة «?»> إلى نهاية البرنامج النصي PHP. وهي ليست ضرورية. بالإضافة إلى ذلك، في سياق الويب، قد تسبب مشكلة إذا تبعها مسافات أو علامات نهاية السطر، والتي يصعب اكتشافها لأنها غير مرئية في محرر النصوص. لذلك، في بقية هذا المستند، سنحذف هذه العلامة بشكل منهجي؛
ملاحظة: في هذا المستند، سنستخدم الكلمة الرئيسية [print] لعرض النص على وحدة التحكم. وهناك طريقة أخرى للقيام بنفس الشيء وهي استخدام الكلمة الرئيسية [echo]. هناك اختلافات طفيفة بين هاتين الكلمتين الرئيسيتين، ولكن في سياق هذا المستند لن يكون هناك أي اختلاف. لذا، إذا كنت تفضل استخدام [echo]، فافعل ذلك.
3.3.2. استخدام NetBeans
يصدر NetBeans العديد من التحذيرات التي من المفيد التحقق منها. لنأخذ على سبيل المثال البرنامج النصي [bases-01.php]:

في السطر 5، يصدر NetBeans تحذيرًا يفيد بأن الملف لا يتوافق مع التوصية PSR-1 (التوصيات القياسية PHP رقم 1). تعد توصيات PSR إرشادات لكتابة كود قياسي، مما يسهل التوافق بين الأنظمة وصيانة الأكواد التي كتبها أشخاص مختلفون. قد يكون ظهور هذه التحذيرات مزعجًا إذا كنت ترغب في مخالفة المعايير عمدًا، على سبيل المثال لأن فريق المشروع لديه معايير أخرى. يمكن تكوين ما نريد التحقق منه أو عدم التحقق منه باستخدام NetBeans:

- في [5]، نجد العناصر التي نريد التحقق منها باستخدام NetBeans؛
- في [6]، مستوى الخطورة المخصص للخطأ الذي أبلغ عنه NetBeans؛

نرى في [7] أنه تم طلب التحقق من أن الكود يتبع التوصيات PSR-0 و PSR-1. ليس هناك أي شيء إلزامي. في مرحلة تعلم اللغة، يُنصح بالتحقق من أكبر عدد ممكن من الخيارات التي يوفرها NetBeans. فمن خلال ذلك نتعلم الكثير. بعد ذلك، سنقوم بتكييف هذا الفحص الذي يجريه NetBeans مع معايير البرمجة الخاصة بفريق المشروع.
لنلقِ نظرة على معايير البرمجة PSR-1 و [8, 9]:
الخيار | التحقق |
| يجب إعلان الثوابت في الفئة MUST بأحرف كبيرة فقط مع فواصل من علامة التسطير. مثال: const TAUX_TVA |
| يجب إعلان أسماء الطرق MUST داخل camelCase(). مثال: public function executeBatchImpots{} |
| يجب إعلان أسماء الخصائص SHOULD بتنسيق $StudlyCaps أو $camelCase أو $under_score (بشكل متسق في نطاق) مثال: public SalaireAnnuel (StudlyCaps)، public salaireAnnuel (camelCase)، public salaire_annuel (under_score) |
| يعلن الملف SHOULD رموزًا جديدة ولا يتسبب في أي آثار جانبية أخرى، أو أنه SHOULD ينفذ منطقًا له آثار جانبية، لكن SHOULD NOT يقوم بكليهما. |
| يجب إعلان أسماء الأنواع في (يستخدم الكود المكتوب لـ 5.2.x وما قبله SHOULD قاعدة تسمية المساحات الاسمية الزائفة التي تعتمد على بادئات Vendor_ في أسماء الأنواع). يوجد كل نوع في ملف منفرد، ويقع ضمن مساحة اسمية من مستوى واحد على الأقل: اسم المورد من المستوى الأعلى. مثال: class EtudiantBoursier {} |
تنص التوصية PSR-1 / 4 على أنه يجب أن يحتوي ملف PHP على:
- إما إعلان نوع (فئات، واجهة)؛
- أو كود قابل للتنفيذ دون إعلان أنواع جديدة؛
هناك توصيات أخرى PHP لا تتحكم فيها NetBeans: PSR-3، PSR-4، PSR-6، PSR-7 و PSR-13.
لتسهيل الأمر، لا تتحقق جميع الأمثلة الواردة في هذا المستند من التوصية PSR-1، لأن ذلك يتطلب توزيع كود الفئات والواجهات في ملفات منفصلة، وهو أمر مرهق للغاية بالنسبة للأمثلة الأساسية. لذا، من الأسهل وضع كل شيء في ملف واحد. بالنسبة لمثال التطبيق المقدم كخيط رفيع في هذا المستند، سعينا إلى الالتزام بأفضل شكل ممكن بالتوصية PSR-1.
تشير بعض تحذيرات NetBeans إلى وجود خطأ محتمل:

يشير التحذير [Unitialized Variables] إلى خطأ محتمل، غالبًا ما يكون خطأً إملائيًا في اسم متغير. وينطبق الأمر نفسه على التحذير [Unused Variables].
وأخيرًا، يُنصح بالتحقق من جميع تحذيرات NetBeans التي تظهر في شكل لوحة في الهامش الأيسر للكود وشرطة صفراء في الهامش الأيمن:


3.4. نطاق المتغيرات
3.4.1. المثال 1
النص البرمجي [bases-02.php] هو كما يلي:
<?php
// نطاق المتغيرات
function f1() {
// يتم استخدام المتغير العام $i
global $i;
$i++;
$j = 10;
print "f1[i,j]=[$i,$j]\n";
}
function f2() {
// يتم استخدام المتغير العام $i
global $i;
$i++;
$j = 20;
print "f2[i,j]=[$i,$j]\n";
}
function f3() {
// يتم استخدام متغير محلي $i
$i = 4;
$j = 30;
print "f3[i,j]=[$i,$j]\n";
}
// اختبارات
$i = 0;
$j = 0; // هذان المتغيران غير معروفين لدالة f
// إلا إذا أعلنت الدالة عنهما صراحةً باستخدام الأمر global
// أنها تريد استخدامهما
f1();
f2();
f3();
print "test[i,j]=[$i,$j]\n";
النتائج:
تعليقات
- السطران 29-30: يحددان متغيرين هما $i و $j في البرنامج الرئيسي. هذه المتغيرات غير معروفة داخل الدوال. وبالتالي، في السطر 9، المتغير $j الخاص بالدالة f1 هو متغير محلي للدالة f1 ويختلف عن المتغير $j في البرنامج الرئيسي. يمكن لأي دالة الوصول إلى المتغير $variable التابع للبرنامج الرئيسي عبر الكلمة المفتاحية global؛
- في السطر 7، تشير التعليمات إلى المتغير العام $i في البرنامج الرئيسي؛
3.4.2. المثال 3
النص البرمجي [bases-03.php] هو كما يلي:
<?php
// نطاق المتغير شامل لجميع كتل الكود
$i = 0; {
$i = 4;
$i++;
}
print "i=$i\n";
النتائج:
تعليقات
في بعض اللغات البرمجية، يكون نطاق المتغير المُعرَّف داخل الأقواس المتعقوفة مقتصرًا على هذه الأقواس: أي أنه لا يكون معروفًا خارجها. تُظهر النتائج أعلاه أن الأمر ليس كذلك في PHP. المتغير $i المُعرَّف في السطر 5 داخل الأقواس هو نفسه المستخدم في السطرين 4 و8 خارجها.
3.5. تغييرات الأنواع
المتغيرات في PHP ليس لها نوع ثابت. فقد يتغير هذا النوع أثناء التنفيذ وفقًا للقيمة المعينة للمتغير. في العمليات التي تتضمن بيانات من أنواع مختلفة، يقوم مترجم PHP بإجراء تحويلات ضمنية لتحويل المعاملات إلى نوع مشترك. قد تشكل هذه التحويلات الضمنية، إذا لم يكن المطور على علم بها، مصدرًا لأخطاء يصعب اكتشافها. فيما يلي، نقدم برنامجًا نصيًّا [bases-04.php] يوضح التحويلات الضمنية والصريحة:
<?php
// أنواع صارمة في تمرير المعلمات
declare(strict_types=1);
// التغييرات الضمنية في الأنواع
// النوع -->bool
print "Conversion vers un booléen------------------------------\n";
showBool("abcd", "abcd");
showBool("", "");
showBool("[1, 2, 3]", [1, 2, 3]);
showBool("[]", []);
showBool("NULL", NULL);
showBool("0.0", 0.0);
showBool("0", 0);
showBool("4.6", 4.6);
function showBool(string $prefixe, $var) : void {
print "(bool) $prefixe : ";
// يتم تحويل $var إلى منطقية تلقائيًا في الاختبار التالي
if ($var) {
print "true";
} else {
print "false";
}
print "\n";
}
تعليقات
- السطر 4: يطلب التحقق الصارم من نوع معلمات الدالة عندما يكون محددًا؛
- السطر 18: تهدف الدالة [showBool] إلى إظهار التحويل الضمني (التلقائي) الذي يقوم به المترجم PHP عندما يتعين تحويل قيمة من أي نوع إلى قيمة منطقية (السطر 21)؛
- السطر 18: لم يتم تعيين نوع للمعلمة $var. وبالتالي، يمكن أن تكون المعلمة الفعلية من أي نوع. أما المعلمة $prefixe فيجب أن تكون من نوع string. ولا تُرجع الدالة showBool أي قيمة (void)؛
- السطر 21: في تعليمة if($var)، يجب تحويل قيمة $var إلى قيمة منطقية (boolean) حتى يتم تقييم if. ومن المثير للدهشة أن المُترجم PHP يعطي إجابة لأي نوع من القيم التي تُقدَّم له؛
- الأسطر 9-16: ستكون قيمة معلمة الدالة [showBool] بالتتابع:
- السطر 9: سلسلة غير فارغة: النتيجة TRUE (حالة الأحرف غير مهمة، TRUE=true)؛
- السطر 10: سلسلة فارغة: النتيجة FALSE؛
- السطر 11: مصفوفة غير فارغة: النتيجة TRUE؛
- السطر 12: مصفوفة فارغة: النتيجة FALSE؛
- السطر 14: العدد الحقيقي 0: النتيجة FALSE؛
- السطر 15: العدد الصحيح 0: النتيجة FALSE؛
- السطر 16: العدد الحقيقي (أو الصحيح) غير الصفر: النتيجة TRUE؛
وهذا ما تظهره لقطات الشاشة التي تم الحصول عليها:
Conversion vers un booléen------------------------------
(bool) abcd : true
(bool) : false
(bool) [1, 2, 3] : true
(bool) [] : false
(bool) NULL : false
(bool) 0.0 : false
(bool) 0 : false
(bool) 4.6 : true
لنكمل كود البرنامج النصي:
//
// تحويلات ضمنية من نوع string إلى نوع رقمي
// سلسلة --> عدد
print "Conversion chaîne vers nombre------------------------------\n";
showNumber("12");
showNumber("45.67");
showNumber("abcd");
function showNumber(string $var) : void {
$nombre = $var + 1;
var_dump($nombre);
print "($var): $nombre\n";
}
تعليقات
- السطر 9: تقبل الدالة [showNumber] معلمة من نوع string ولا تُرجع أي نتيجة (void)؛
- السطر 10: تُستخدم هذه المعلمة في عملية حسابية، مما سيجبر مترجم PHP على محاولة تحويل $var إلى عدد؛
- السطر 5: سيحول السلسلة «12» إلى عدد صحيح 12؛
- السطر 6: سيحول السلسلة “45.67” إلى عدد حقيقي يساوي 45.67؛
- السطر 7: سيصدر تحذيرًا ولكنه سيقوم مع ذلك بتحويل السلسلة “abcd” إلى الرقم 0؛
فيما يلي نتائج التنفيذ:
لنكمل كود البرنامج النصي:
// تحويلات صريحة بين الأنواع
// إلى int
showInt("12.45");
showInt(67.8);
showInt(TRUE);
showInt(NULL);
function showInt($var) : void {
print "paramètre : ";
var_dump($var);
print "\n";
print "résultat de la conversion : ";
var_dump((int) $var);
print "\n";
}
تعليقات
- السطر 21: تستقبل الدالة [showInt] معلمة من أي نوع ولا تُرجع أي نتيجة. وهي تحاول تحويل المعلمة $var إلى عدد صحيح في السطر 26. بشكل عام، لتغيير متغير $var إلى نوع T، نكتب (T) $var حيث يمكن أن يكون T: int، integer، bool، boolean، float، double، real، string، array، object، unset؛
- السطر 16: يحول السلسلة “12.45” إلى عدد صحيح 12؛
- السطر 17: يحول العدد الحقيقي 67.8 إلى عدد صحيح 67؛
- السطر 18: يحول القيمة المنطقية TRUE إلى العدد الصحيح 1 (والقيمة المنطقية FALSE إلى العدد الصحيح 0)؛
- السطر 19: يحول المؤشر NULL إلى عدد صحيح يساوي 0؛
وهذا ما تظهره شاشات العرض:
نواصل دراسة البرنامج النصي من خلال التحويل الصريح للقيم إلى النوع العائم:
// إلى float
showFloat("12.45");
showFloat(67);
showFloat(TRUE);
showFloat(NULL);
function showFloat($var) : void {
print "paramètre : ";
var_dump($var);
print "\n";
print "résultat de la conversion : ";
var_dump((float) $var);
print "\n";
}
تعليقات
- السطر 35: تستقبل الدالة [showFloat] معلمة من أي نوع ولا تُرجع أي نتيجة؛
- السطر 40: يتم تحويل قيمة هذا المعامل صراحةً إلى float؛
- السطر 30: يتم تحويل السلسلة "12.45" إلى العدد الحقيقي 12.45؛
- السطر 31: يتم تحويل العدد الصحيح 67 إلى العدد الحقيقي 67؛
- السطر 32: يتم تحويل القيمة المنطقية TRUE إلى العدد الحقيقي 1 (ويتم تحويل القيمة FALSE إلى العدد 0)؛
- السطر 33: تم تحويل المؤشر NULL إلى العدد الحقيقي 0؛
وهذا ما تظهره نتائج الشاشة:
نواصل عرض البرنامج النصي بدراسة عمليات التحويل إلى نوع string:
// إلى سلسلة
showstring(5);
showString(6.7);
showString(FALSE);
showString(NULL);
function showString($var) : void {
print "paramètre : ";
var_dump($var);
print "\n";
print "résultat de la conversion : ";
var_dump((string) $var);
print "\n";
}
- السطر 49: تتلقى الدالة [showString] معلمة من أي نوع ولا تُرجع أي نتيجة؛
- السطر 54: يتم تحويل قيمة المعلمة إلى نوع string؛
- السطر 44: سيتم تحويل العدد الصحيح 5 إلى السلسلة «5»؛
- السطر 45: سيتم تحويل العدد الحقيقي 6.7 إلى السلسلة "6.7"؛
- السطر 46: سيتم تحويل القيمة المنطقية FALSE إلى سلسلة فارغة؛
- السطر 47: سيتم تحويل المؤشر NULL إلى سلسلة فارغة؛
فيما يلي نتائج الشاشة:
3.6. الجداول
3.6.1. الجداول التقليدية أحادية البعد
النص البرمجي [bases-05.php] هو كما يلي:
<?php
// مصفوفات تقليدية
// التهيئة
$tab1 = array(0, 1, 2, 3, 4, 5);
// التصفح - 1
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
print "tab1[$i]=$tab1[$i]\n";
}
// التصفح - 2
print "tab1 a " . count($tab1) . " éléments\n";
reset($tab1);
while (list($clé, $valeur) = each($tab1)) {
print "tab1[$clé]=$valeur\n";
}
// إضافة عناصر
$tab1[] = $i++;
$tab1[] = $i++;
// التصفح - 3
print "tab1 a " . count($tab1) . " éléments\n";
$i = 0;
foreach ($tab1 as $élément) {
print "tab1[$i]=$élément\n";
$i++;
}
// حذف العنصر الأخير
array_pop($tab1);
// المسار - 4
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
print "tab1[$i]=$tab1[$i]\n";
}
// حذف العنصر الأول
array_shift($tab1);
// التنقل - 5
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
print "tab1[$i]=$tab1[$i]\n";
}
// إضافة في نهاية الجدول
array_push($tab1, -2);
// التنقل - 6
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
print "tab1[$i]=$tab1[$i]\n";
}
// إضافة في بداية الجدول
array_unshift($tab1, -1);
// التنقل - 7
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
print "tab1[$i]=$tab1[$i]\n";
}
النتائج:
tab1 a 6 éléments
tab1[0]=0
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1 a 6 éléments
Deprecated: The each() function is deprecated. This message will be suppressed on further calls in C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_04.php on line 14
tab1[0]=0
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1 a 8 éléments
tab1[0]=0
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1[6]=6
tab1[7]=7
tab1 a 7 éléments
tab1[0]=0
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1[6]=6
tab1 a 6 éléments
tab1[0]=1
tab1[1]=2
tab1[2]=3
tab1[3]=4
tab1[4]=5
tab1[5]=6
tab1 a 7 éléments
tab1[0]=1
tab1[1]=2
tab1[2]=3
tab1[3]=4
tab1[4]=5
tab1[5]=6
tab1[6]=-2
tab1 a 8 éléments
tab1[0]=-1
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1[6]=6
tab1[7]=-2
تعليقات
يُظهر البرنامج أعلاه عمليات معالجة مصفوفة من القيم. توجد طريقتان لكتابة المصفوفات في PHP:
يُسمى المصفوفة 1 مصفوفة، ويُسمى المصفوفة 2 قاموسًا أو مصفوفة ترابطية حيث تُدوّن العناصر على النحو التالي: المفتاح => القيمة. تشير الصيغة $contraires["beau"] إلى القيمة المرتبطة بالمفتاح "جميل". وهي هنا السلسلة "قبيح". المصفوفة 1 ليست سوى شكل آخر من أشكال القاموس ويمكن تدوينها على النحو التالي:
وبذلك نحصل على $tableau[2]="trois". في النهاية، لا يوجد سوى القواميس. في حالة مصفوفة تقليدية مكونة من n عنصرًا، تكون المفاتيح هي الأعداد الصحيحة من النطاق [0,n-1].
- السطر 14: تتيح الدالة each($tableau) تصفح القاموس. وعند كل استدعاء، تُرجع زوجًا (مفتاح، قيمة) منه. وكما يظهر في السطر 10 من النتائج، أصبحت الدالة each قديمة الآن في الإصدار PHP 7؛
- السطر 13: تضع الدالة reset($dictionnaire) الدالة each على الزوج الأول (مفتاح، قيمة) من القاموس.
- السطر 14: تتوقف الحلقة while عندما تُرجع الدالة each زوجًا فارغًا في نهاية القاموس. وهنا يتم إجراء تحويل ضمني: حيث يتم تحويل الزوج الفارغ إلى القيمة المنطقية FALSE؛
- السطر 18: تضيف صيغة $tableau[]=value العنصر valeur كآخر عنصر في $tableau؛
- السطر 23: يتم تصفح المصفوفة باستخدام foreach. يسمح هذا العنصر النحوي بتصفح قاموس، وبالتالي مصفوفة، وفقًا لنظامين نحويين:
تُرجع الصيغة الأولى زوجًا (clé,valeur) في كل تكرار، بينما تُرجع الصيغة الثانية العنصر valeur فقط من القاموس.
- السطر 28: الدالة array_pop($tableau) تحذف العنصر الأخير من $tableau؛
- السطر 35: تقوم الدالة array_shift($tableau) بحذف العنصر الأول من $tableau؛
- السطر 42: تضيف الدالة array_push($tableau,قيمة) valeur كعنصر أخير في $tableau؛
- السطر 49: تضيف الدالة array_unshift($tableau، القيمة) valeur كأول عنصر في $tableau؛
3.6.2. القاموس أو المصفوفة الترابطية
النص البرمجي [bases-06.php] هو كما يلي:
<?php
// القواميس
$conjoints = ["Pierre" => "Gisèle", "Paul" => "Virginie", "Jacques" => "Lucette", "Jean" => ""];
// مسار - 1
print "Nombre d'éléments du dictionnaire : " . count($conjoints) . "\n";
reset($conjoints);
while (list($clé, $valeur) = each($conjoints)) {
print "conjoints[$clé]=$valeur\n";
}
// فرز القاموس حسب المفتاح
ksort($conjoints);
// التصفح - 2
reset($conjoints);
while (list($clé, $valeur) = each($conjoints)) {
print "conjoints[$clé]=$valeur\n";
}
// قائمة مفاتيح القاموس
$clés = array_keys($conjoints);
for ($i = 0; $i < count($clés); $i++) {
print "clés[$i]=$clés[$i]\n";
}
// قائمة قيم القاموس
$valeurs = array_values($conjoints);
for ($i = 0; $i < count($valeurs); $i++) {
print "valeurs[$i]=$valeurs[$i]\n";
}
// البحث عن مفتاح
existe($conjoints, "Jacques");
existe($conjoints, "Lucette");
existe($conjoints, "Jean");
// حذف مفتاح وقيمة
unset($conjoints["Jean"]);
print "Nombre d'éléments du dictionnaire : " . count($conjoints) . "\n";
foreach ($conjoints as $clé => $valeur) {
print "conjoints[$clé]=$valeur\n";
}
// النهاية
exit;
function existe($conjoints, $mari) {
// التحقق من وجود المفتاح $mari في القاموس $conjoints
if (isset($conjoints[$mari])) {
print "La clé [$mari] existe associée à la valeur [$conjoints[$mari]]\n";
} else {
print "La clé [$mari] n'existe pas\n";
}
}
النتائج:
Nombre d'éléments du dictionnaire : 4
Deprecated: The each() function is deprecated. This message will be suppressed on further calls in C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_05.php on line 8
conjoints[Pierre]=Gisèle
conjoints[Paul]=Virginie
conjoints[Jacques]=Lucette
conjoints[Jean]=
conjoints[Jacques]=Lucette
conjoints[Jean]=
conjoints[Paul]=Virginie
conjoints[Pierre]=Gisèle
clés[0]=Jacques
clés[1]=Jean
clés[2]=Paul
clés[3]=Pierre
valeurs[0]=Lucette
valeurs[1]=
valeurs[2]=Virginie
valeurs[3]=Gisèle
La clé [Jacques] existe associée à la valeur [Lucette]
La clé [Lucette] n'existe pas
La clé [Jean] existe associée à la valeur []
Nombre d'éléments du dictionnaire : 3
conjoints[Jacques]=Lucette
conjoints[Paul]=Virginie
conjoints[Pierre]=Gisèle
تعليقات
يطبق الكود السابق على قاموس ما سبق تناوله سابقًا بالنسبة لمصفوفة بسيطة. لن نعلق إلا على العناصر الجديدة:
- السطر 12: تسمح الدالة ksort (key sort) بفرز القاموس حسب الترتيب الطبيعي للمفتاح؛
- السطر 19: تعرض الدالة array_keys($dictionnaire) قائمة مفاتيح القاموس في شكل مصفوفة؛
- السطر 24: تعرض الدالة array_values($dictionnaire) قائمة قيم القاموس في شكل جدول؛
- السطر 43: تعرض الدالة isset($variable) القيمة TRUE إذا تم تعريف المتغير $variable، وإلا تعرض القيمة FALSE؛
- السطر 33: الدالة unset($variable) تحذف المتغير $variable.
3.6.3. الجداول متعددة الأبعاد
النص البرمجي [bases-07.php] هو كما يلي:
<?php
// الجداول التقليدية متعددة الأبعاد
// التهيئة
$multi = array(array(0, 1, 2), array(10, 11, 12, 13), array(20, 21, 22, 23, 24));
// التصفح
for ($i1 = 0; $i1 < count($multi); $i1++) {
for ($i2 = 0; $i2 < count($multi[$i1]); $i2++) {
print "multi[$i1][$i2]=" . $multi[$i1][$i2] . "\n";
}
}
// قواميس متعددة الأبعاد
// التهيئة
$multi = array("zéro" => array(0, 1, 2), "un" => array(10, 11, 12, 13), "deux" => array(20, 21, 22, 23, 24));
// التصفح
foreach ($multi as $clé => $valeur) {
for ($i2 = 0; $i2 < count($valeur); $i2++) {
print "multi[$clé][$i2]=" . $multi[$clé][$i2] . "\n";
}
}
النتائج:
multi[0][0]=0
multi[0][1]=1
multi[0][2]=2
multi[1][0]=10
multi[1][1]=11
multi[1][2]=12
multi[1][3]=13
multi[2][0]=20
multi[2][1]=21
multi[2][2]=22
multi[2][3]=23
multi[2][4]=24
multi[zéro][0]=0
multi[zéro][1]=1
multi[zéro][2]=2
multi[un][0]=10
multi[un][1]=11
multi[un][2]=12
multi[un][3]=13
multi[deux][0]=20
multi[deux][1]=21
multi[deux][2]=22
multi[deux][3]=23
multi[deux][4]=24
تعليقات
- السطر 5: عناصر المصفوفة $multi هي نفسها مصفوفات؛
- السطر 14: يصبح المصفوفة $multi قاموسًا (clé,valeur) حيث يمثل كل valeur مصفوفة؛
3.7. سلاسل الأحرف
3.7.1. الترميز
النص البرمجي [bases-08.php] هو كما يلي:
<?php
// ترميز السلاسل
$chaine1 = "un";
$chaine2 = 'un';
print "[$chaine1,$chaine2]\n";
?>
النتائج:
3.7.2. المقارنة
النص البرمجي [bases-09.php] هو التالي:
<?php
// الالتزام الصارم بنوع معلمات الدوال
declare(strict_types=1);
// دالة المقارنة
function compareModele2Chaine(string $chaine1, string $chaine2): void {
// مقارنة السلسلة 1 بالسلسلة 2
if ($chaine1 === $chaine2) {
print "[$chaine1] est égal à [$chaine2]\n";
} else {
print "[$chaine1] est différent de [$chaine2]\n";
}
}
// اختبارات مقارنة السلاسل
compareModele2Chaine("abcd", "abcd");
compareModele2Chaine("", "");
compareModele2Chaine("1", "");
exit;
النتائج:
[abcd] est égal à [abcd]
[] est égal à []
[1] est différent de []
تعليقات
- السطر 9 من الكود: كان من الممكن استخدام عامل المقارنة == بدلاً من ===. هذا العامل الأخير أكثر تقييدًا من حيث أنه يشترط أن يكون نوعي المعاملين متطابقين. تجدر الإشارة إلى أنه كان من الممكن هنا استبداله بعامل == نظرًا لأن نوعي المعلمتين محددان بـ string في توقيع الدالة؛
3.7.3. الروابط بين السلاسل والمصفوفات
النص البرمجي [bases-10.php] هو التالي:
<?php
// تحويل سلسلة إلى مصفوفة
$chaine = "1:2:3:4";
$tab = explode(":", $chaine);
// تجول في المصفوفة
print "tab a " . count($tab) . " éléments\n";
for ($i = 0; $i < count($tab); $i++) {
print "tab[$i]=$tab[$i]\n";
}
// تحويل المصفوفة إلى سلسلة
$chaine2 = implode(":", $tab);
print "chaine2=$chaine2\n";
// إضافة حقل فارغ
$chaine .= ":";
print "chaîne=$chaine\n";
$tab = explode(":", $chaine);
// التنقل عبر المصفوفة
print "tab a " . count($tab) . " éléments\n";
for ($i = 0; $i < count($tab); $i++) {
print "tab[$i]=$tab[$i]\n";
} // لدينا الآن 5 عناصر، آخرها فارغ
// لنضف حقلًا فارغًا مرة أخرى
$chaine .= ":";
print "chaîne=$chaine\n";
$tab = explode(":", $chaine);
// تصفح المصفوفة
print "tab a " . count($tab) . " éléments\n";
for ($i = 0; $i < count($tab); $i++) {
print "tab[$i]=$tab[$i]\n";
} // لدينا الآن 6 عناصر، وآخر عنصرين فارغين
النتائج:
tab a 4 éléments
tab[0]=1
tab[1]=2
tab[2]=3
tab[3]=4
chaine2=1:2:3:4
chaîne=1:2:3:4:
tab a 5 éléments
tab[0]=1
tab[1]=2
tab[2]=3
tab[3]=4
tab[4]=
chaîne=1:2:3:4::
tab a 6 éléments
tab[0]=1
tab[1]=2
tab[2]=3
tab[3]=4
tab[4]=
tab[5]=
تعليقات
- السطر 5: تسمح الدالة explode($séparateur,$chaine) باستخراج حقول $chaine المفصولة بـ $séparateur. وبالتالي، تسمح الدالة explode(":",$chaine) باسترداد عناصر $chaine المفصولة بالسلسلة ":" في شكل مصفوفة؛
- السطر 12: تقوم الدالة implode($séparateur,$tableau) بالعملية العكسية للدالة explode. وهي تُرجع سلسلة أحرف مكونة من عناصر $tableau مفصولة بـ $séparateur؛
3.7.4. التعبيرات النمطية
النص البرمجي [bases-11.php] هو كما يلي:
<?php
// نوع صارم لمعلمات الدوال
declare (strict_types=1);
// التعبيرات النمطية في PHP
// استخراج الحقول المختلفة من سلسلة
// النمط: سلسلة من الأرقام محاطة بأي أحرف
// نريد استخراج سلسلة الأرقام فقط
$modèle = "/(\d+)/";
// مقارنة السلسلة بالنموذج
compareModele2Chaine($modèle, "xyz1234abcd");
compareModele2Chaine($modèle, "12 34");
compareModele2Chaine($modèle, "abcd");
// النمط: سلسلة من الأرقام محاطة بأحرف عشوائية
// نريد سلسلة الأرقام بالإضافة إلى الحقول التي تليها وتسبقها
$modèle = "/^(.*?)(\d+)(.*?)$/";
// نقوم بمقارنة السلسلة بالنموذج
compareModele2Chaine($modèle, "xyz1234abcd");
compareModele2Chaine($modèle, "12 34");
compareModele2Chaine($modèle, "abcd");
// القالب - تاريخ بتنسيق يوم/شهر/سنة
$modèle = "/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/";
compareModele2Chaine($modèle, "10/05/97");
compareModele2Chaine($modèle, " 04/04/01 ");
compareModele2Chaine($modèle, "5/1/01");
// القالب - رقم عشري
$modèle = "/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/";
compareModele2Chaine($modèle, "187.8");
compareModele2Chaine($modèle, "-0.6");
compareModele2Chaine($modèle, "4");
compareModele2Chaine($modèle, ".6");
compareModele2Chaine($modèle, "4.");
compareModele2Chaine($modèle, " + 4");
// النهاية
exit;
// --------------------------------------------------------------------------
function compareModele2Chaine(string $modèle, string $chaîne): void {
// يقارن السلسلة $chaîne بالنموذج $modèle
// مقارنة السلسلة بالنموذج
$champs = [];
$correspond = preg_match($modèle, $chaîne, $champs);
// عرض النتائج
print "\nRésultats($modèle,$chaîne)\n";
if ($correspond) {
for ($i = 0; $i < count($champs); $i++) {
print "champs[$i]=$champs[$i]\n";
}
} else {
print "La chaîne [$chaîne] ne correspond pas au modèle [$modèle]\n";
}
}
النتائج:
Résultats(/(\d+)/,xyz1234abcd)
champs[0]=1234
champs[1]=1234
Résultats(/(\d+)/,12 34)
champs[0]=12
champs[1]=12
Résultats(/(\d+)/,abcd)
La chaîne [abcd] ne correspond pas au modèle [/(\d+)/]
Résultats(/^(.*?)(\d+)(.*?)$/,xyz1234abcd)
champs[0]=xyz1234abcd
champs[1]=xyz
champs[2]=1234
champs[3]=abcd
Résultats(/^(.*?)(\d+)(.*?)$/,12 34)
champs[0]=12 34
champs[1]=
champs[2]=12
champs[3]= 34
Résultats(/^(.*?)(\d+)(.*?)$/,abcd)
La chaîne [abcd] ne correspond pas au modèle [/^(.*?)(\d+)(.*?)$/]
Résultats(/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/,10/05/97)
champs[0]=10/05/97
champs[1]=10
champs[2]=05
champs[3]=97
Résultats(/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/, 04/04/01 )
champs[0]= 04/04/01
champs[1]=04
champs[2]=04
champs[3]=01
Résultats(/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/,5/1/01)
La chaîne [5/1/01] ne correspond pas au modèle [/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/]
Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,187.8)
champs[0]=187.8
champs[1]=
champs[2]=187.8
Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,-0.6)
champs[0]=-0.6
champs[1]=-
champs[2]=0.6
Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,4)
champs[0]=4
champs[1]=
champs[2]=4
Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,.6)
champs[0]=.6
champs[1]=
champs[2]=.6
Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,4.)
champs[0]=4.
champs[1]=
champs[2]=4.
Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/, + 4)
champs[0]= + 4
champs[1]=+
champs[2]=4
تعليقات
- نستخدم هنا التعبيرات النمطية لاستخراج الحقول المختلفة من سلسلة أحرف. تتيح التعبيرات النمطية تجاوز حدود الدالة implode. ويتمثل المبدأ في مقارنة سلسلة أحرف بسلسلة أخرى تسمى modèle باستخدام الدالة preg_match:
$correspond = preg_match($modèle, $chaîne, $champs);
تُرجع الدالة preg_match قيمة منطقية TRUE إذا كان من الممكن العثور على modèle في chaîne. إذا كان الأمر كذلك، فإن $champs[0] تمثل السلسلة الفرعية المطابقة للنموذج. من ناحية أخرى، إذا كان modèle يحتوي على نماذج فرعية بين قوسين، فإن $champs[1] هو الجزء من $chaîne المطابق للنموذج الفرعي الأول، و $champs[2] هو الجزء من $chaîne المطابق للنموذج الفرعي الثاني، وهكذا دواليك…
لنأخذ المثال الأول. يتم تعريف النموذج في السطر 10: وهو يشير إلى سلسلة من رقم واحد أو أكثر (+) من الأرقام (\d) موضوعة في أي مكان في السلسلة. علاوة على ذلك، يحدد النموذج نموذجًا فرعيًا محاطًا بأقواس؛
- السطر 12: يُقارن النموذج /(\d+)/ (سلسلة من رقم واحد أو أكثر في أي مكان في السلسلة) بالسلسلة "xyz1234abcd". نلاحظ أن السلسلة الفرعية 1234 تتطابق مع النموذج. وبالتالي، فإن $champs[0] يساوي «1234». بالإضافة إلى ذلك، يحتوي النموذج على نماذج فرعية بين قوسين. سيكون لدينا $champs[1]="1234"؛
- السطر 13: يتم مقارنة النمط /(\d+)/ بالسلسلة "12 34". نلاحظ أن السلسلتين الفرعيتين 12 و34 تتطابقان مع النمط. تتوقف المقارنة عند أول سلسلة فرعية تتطابق مع النمط. وبالتالي، سيكون لدينا $champs[0]=12 و $champs[1]=12؛
- السطر 14: يتم مقارنة النمط /(\d+)/ بالسلسلة "abcd". لم يتم العثور على أي تطابق؛
دعونا نوضح الأنماط المستخدمة في بقية الكود:
$modèle = "/^(.*?)(\d+)(.*?)$/";
يمثل بداية السلسلة (^)، ثم صفر أو أكثر (*) من الأحرف العشوائية (.)، ثم رقم واحد أو أكثر (+)، ثم مرة أخرى صفر أو أكثر (*) من الأحرف العشوائية (.). يشير النمط (.*) إلى 0 أو أكثر من أي حرف. سيتطابق هذا النمط مع أي سلسلة. وبالتالي، لن يتم العثور على النمط /^(.*)(\d+)(.*)$/ أبدًا لأن النمط الفرعي الأول (.*) سيستوعب السلسلة بأكملها. أما النمط (.*?)(\d+) فيشير إلى صفر أو أكثر من الأحرف العشوائية حتى النمط الفرعي التالي (؟)، وهو هنا \d+. وبالتالي، لم تعد الأرقام تُستوعب الآن بواسطة النمط (.*). لذا، فإن النمط أعلاه يتطابق مع [début de chaîne (^), une suite de caractères quelconques (.*?), une suite d'un ou plusieurs chiffres (\d+), une suite de caractères quelconques (.*?), la fin de la chaîne ($)].
$modèle = "/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/";
يتطابق مع [début de chaîne (^), 2 chiffres (\d\d), le caractère / (\/), 2 chiffres, /, 2 chiffres, une suite de 0 ou plusieurs espaces (\s*), la fin de chaîne ($)].
$modèle = "/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/";
يتطابق مع بداية السلسلة (^)، صفر أو أكثر من المسافات (\s*)، علامة + أو - [+|-] تظهر مرة واحدة أو أكثر (؟)، سلسلة من صفر أو أكثر من المسافات (\s*)، رقم واحد أو أكثر متبوعًا بعلامة الفاصلة العشرية متبوعة بصفر أو أكثر من الأرقام (\d+\.\d*) أو (|) علامة الفاصلة العشرية (\.) متبوعة برقم واحد أو أكثر (\d+) أو (|) رقم واحد أو أكثر (\d+)، سلسلة من صفر أو أكثر من المسافات (\s*)].
ملاحظة: يشير المصطلح [espace] في التعبيرات النمطية إلى مجموعة من الأحرف: مسافة، قفزة سطر \n، علامة جدولة \t، عودة إلى السطر \r، قفزة صفحة \f…
3.8. الوظائف
3.8.1. طريقة تمرير المعلمات
النص البرمجي [base-12.php] هو كما يلي:
<?php
// طريقة تمرير معلمات الدالة
// الالتزام الصارم بنوع المعلمات
declare(strict_types=1);
function f(int &$i, int $j): void {
// سيتم الحصول على $i بالمرجع
// سيتم الحصول على $j بالقيمة
$i++;
$j++;
print "f[i,j]=[$i,$j]\n";
}
// اختبارات
$i = 0;
$j = 0;
//و $i و $j تم تمريرها إلى الدالة f
f($i, $j);
print "test[i,j]=[$i,$j]\n";
النتائج:
تعليقات
يُظهر الكود أعلاه طريقتين لتمرير المعلمات إلى دالة. لنأخذ المثال التالي:
- السطر 1: يحدد المعلمات الشكلية $a و $b للدالة f. تقوم هذه الدالة بمعالجة هذين المعلمتين الشكليتين وتُرجع نتيجة؛
- السطر 7: استدعاء الدالة f بمعلمتين فعليتين هما $i و $j. يتم تحديد الروابط بين المعلمات الشكلية ($a، $b) والمعلمات الفعلية ($i، $j) من خلال السطرين 1 و7:
- &$a: تشير علامة & إلى أن المعلمة الشكلية $a ستأخذ كقيمة عنوان المعلمة الفعلية $i. بعبارة أخرى، $a و $i هما مرجعان لنفس موقع الذاكرة. إن التعامل مع المعلمة الشكلية $a يعادل التعامل مع المعلمة الفعلية $i. وهذا ما يوضحه تنفيذ الكود. يناسب هذا النمط من التمرير معلمات الإخراج والبيانات الضخمة مثل المصفوفات والقواميس. ويُطلق على هذا النمط من التمرير اسم «التمرير بالمرجع».
- $b: ستتخذ المعلمة الشكلية $b القيمة نفسها التي تتخذها المعلمة الفعلية $j. وهذا هو التمرير بالقيمة. المعلمات الشكلية والفعلية هما متغيران مختلفان. ولا يؤثر التعامل مع المعلمة الشكلية $b بأي شكل من الأشكال على المعلمة الفعلية $j. وهذا ما يوضحه تنفيذ الكود. وتناسب طريقة التمرير هذه معلمات الإدخال.
- لنفترض أن الدالة échange تقبل معلمتين شكليتين $a و $b. تقوم الدالة بتبديل قيم هذين المعلمتين. وبالتالي، عند إجراء استدعاء التبديل ($i، $j)، يتوقع الكود المستدعي أن يتم تبديل قيم المعلمتين الفعليتين. وبالتالي فهما معلمتان مخرجات (يتم تعديلهما). لذا سنكتب:
يُظهر البرنامج النصي التالي [base-13.php] أمثلة أخرى:
<?php
// أنواع في الوضع الصارم
// declare(strict_types = 1);
// طريقة تمرير المعلمات
function f(&$i, $j) {
// سيتم الحصول على $i بالمرجع
// سيتم الحصول على $j بالقيمة
$i++;
$j++;
print "f[i,j]=[$i,$j]\n";
}
function g(int &$i, int $j) : void {
// سيتم الحصول على $i بالمرجع
// $j سيتم الحصول عليه بالقيمة
$i++;
$j++;
print "g[i,j]=[$i,$j]\n";
}
// اختبارات
$i = 0;
$j = 0;
// يتم تمرير $i و $j إلى الدالة f
f($i, $j);
print "test[i,j]=[$i,$j]\n";
// يتم تمرير $i و $j إلى الدالة g
g($i, $j);
print "test[i,j]=[$i,$j]\n";
// يتم تمرير معلمات غير صحيحة إلى f
$a=5.3;
$b=6.2;
f($a, $b);
print "test[a,b]=[$a,$b]\n";
// يتم تمرير معلمات غير صحيحة إلى f
$a=5.3;
$b=6.2;
g($a, $b);
print "test[a,b]=[$a,$b]\n";
تعليقات
- الأسطر 8-14: الدالة f التي تمت دراستها في الفقرة السابقة، لكن لم يتم تحديد أنواع المعلمات؛
- الأسطر 16-22: الدالة g تقوم بنفس عمل الدالة f ولكننا نحدد نوع المعلمات المتوقعة – وهذا أمر جديد PHP 7. ننتظر معلمتين من النوع int. نريد أن نرى ما يحدث عندما لا يكون للمعلمة الفعلية التي تم تمريرها إلى الدالة النوع الذي تتوقعه الدالة؛
- الأسطر 25-26: $i و $j هما عددان صحيحان؛
- السطران 28-29: استدعاء الدالة f بمعلمات من النوع المتوقع؛
- السطران 31-32: استدعاء الدالة g بمعلمات من النوع المتوقع؛
- السطران 34-35: المتغيران $a و $b من النوع float؛
- السطران 36-37: استدعاء الدالة f بمعلمات ليست من النوع المتوقع؛
- السطران 41-42: استدعاء الدالة g بمعلمات ليست من النوع المتوقع؛
النتائج
- تُظهر السطران 5 و6 أن الدالة f قد استقبلت المعلمتين من النوع float وعملت بهما؛
- تُظهر السطور 7-8 أن الدالة g قد قبلت المعلمتين من النوع float لكنها حوّلتهما إلى النوع int (السطر 7)؛
الآن لن نزيل التعليق عن السطر 4:
تشير هذه التعليمات إلى ضرورة الالتزام بأنواع المعلمات الشكلية. وإذا لم يحدث ذلك، يتم الإبلاغ عن خطأ. وتصبح نتائج التنفيذ عندئذٍ كما يلي:
- السطران 9-10: أطلق المُفسر PHP 7 استثناءً للإشارة إلى أن المعلمة الأولى التي تم تمريرها إلى الدالة g لم تكن من النوع الصحيح. يُنصح بالالتزام الصارم بأنواع المعلمات، كلما أمكن ذلك، للكشف عن أخطاء استدعاء الدوال؛
3.8.2. النتائج التي تعطيها الدالة
النص البرمجي [base-15.php] هو التالي:
<?php
// الأنواع في الوضع الصارم
declare(strict_types=1);
// النتائج التي تُرجعها الدالة
// يمكن للدالة أن تُرجع عدة قيم في صفيف
list($res1, $res2, $res3) = f1(10);
print "[$res1,$res2,$res3]\n";
$res = f1(10);
for ($i = 0; $i < count($res); $i++) {
print "f1 : res[$i]=$res[$i]\n";
}
// يمكن للدالة أن تُرجع كائنًا
$res = f2(10);
print "f2 : [$res->res1,$res->res2,$res->res3]\n";
// كائن من أي نوع؟
print "nature de l'objet : ";
var_dump($res);
print "\n";
// نقوم بنفس الشيء مع الدالة f3
$res = f3(10);
print "f3 : [$res->res1,$res->res2,$res->res3]\n";
// ما طبيعة هذا الكائن؟
print "nature de l'objet : ";
var_dump($res);
print "\n";
// النهاية
exit;
// الدالة f1
function f1(int $valeur): array {
// تُرجع مصفوفة ($valeur+1،$valeur+2،$valeur+3)
return array($valeur + 1, $valeur + 2, $valeur + 3);
}
// الدالة f2
function f2(int $valeur): object {
// تُرجع كائنًا ($valeur+1,$valeur+2,$valeur+3)
$res->res1 = $valeur + 1;
$res->res2 = $valeur + 2;
$res->res3 = $valeur + 3;
// تُرجع الكائن
return $res;
}
// الدالة f3 - تقوم بنفس ما تقوم به الدالة f2
function f3(int $valeur): object {
// تُرجع كائنًا ($valeur+1,$valeur+2,$valeur+3)
$res = new stdclass();
$res->res1 = $valeur + 1;
$res->res2 = $valeur + 2;
$res->res3 = $valeur + 3;
// تُرجع الكائن
return $res;
}
النتائج
[11,12,13]
f1 : res[0]=11
f1 : res[1]=12
f1 : res[2]=13
Warning: Creating default object from empty value in C:\Data\st-2019\dev\php7\php5-exemples\exemples\bases\base-15.php on line 43
f2 : [11,12,13]
nature de l'objet : object(stdClass)#1 (3) {
["res1"]=>
int(11)
["res2"]=>
int(12)
["res3"]=>
int(13)
}
f3 : [11,12,13]
nature de l'objet : object(stdClass)#2 (3) {
["res1"]=>
int(11)
["res2"]=>
int(12)
["res3"]=>
int(13)
}
تعليقات
- يُظهر البرنامج السابق أن الدالة PHP يمكنها إرجاع مجموعة من النتائج وليس نتيجة واحدة، في شكل مصفوفة أو كائن. وسيتم توضيح مفهوم الكائن لاحقًا؛
- الأسطر 35-38: تُرجع الدالة f1 عدة قيم في شكل مصفوفة (array)؛
- الأسطر 41-48: تُرجع الدالة f2 عدة قيم في شكل كائن (object)؛
- الأسطر 51-59: الدالة f3 مطابقة للدالة f2 باستثناء أنها تنشئ كائنًا بشكل صريح، في السطر 53؛
- السطر 6 من النتائج يصدر تحذيرًا (warning) يشير إلى أن PHP اضطر إلى إنشاء كائن افتراضي في السطر 43 من الكود، أي عند استخدام الترميز [$res→res1]. تتيح الدالة var_dump في السطر 20 من الكود الوصول إلى نوع الكائن ومحتواه. في النتائج، نلاحظ ما يلي:
- السطر 8: الكائن الذي تم إنشاؤه افتراضيًا هو من النوع stdClass؛
- السطران 9-10: الخاصية res1 من النوع entier وقيمتها 11؛
- إلخ…
- لتجنب التحذير الوارد في السطر 6 من النتائج، نقوم بإنشاء كائن من النوع stdClass بشكل صريح في السطر 53 من الدالة f3؛
3.9. الملفات النصية
النص البرمجي [bases-16.php] هو التالي:
<?php
// الالتزام الصارم بنوع معلمات الدوال
declare (strict_types=1);
// معالجة متسلسلة لملف نصي
// وهو عبارة عن مجموعة من الأسطر بالصيغة login:pwd:uid:gid:infos:dir:shell
// يتم وضع كل سطر في قاموس بالصيغة login => uid:gid:infos:dir:shell
// يتم تحديد اسم الملف
$INFOS = "infos.txt";
// يتم فتحه لإنشائه
if (!$fic = fopen($INFOS, "w")) {
print "Erreur d'ouverture du fichier $INFOS en écriture\n";
exit;
}
// يتم إنشاء محتوى عشوائي
for ($i = 0; $i < 100; $i++) {
fputs($fic, "login$i:pwd$i:uid$i:gid$i:infos$i:dir$i:shell$i\n");
}
// يتم إغلاق الملف
fclose($fic);
// يتم استغلاله - تحافظ fgets على علامة نهاية السطر
// وهذا يمنع استرداد سلسلة فارغة عند قراءة سطر فارغ
// يتم فتحه للقراءة
if (!$fic = fopen($INFOS, "r")) {
print "Erreur d'ouverture du fichier $INFOS en lecture\n";
exit;
}
// يبلغ عدد أحرف الأسطر أقل من 1000 حرف
// تتوقف قراءة السطر عند علامة نهاية السطر
// أو علامة نهاية الملف
while ($ligne = fgets($fic, 1000)) {
// يتم حذف علامة نهاية السطر إن وجدت
$ligne = cutNewLineChar($ligne);
// يتم وضع السطر في مصفوفة
$infos = explode(":", $ligne);
// يتم استرداد اسم المستخدم
$login = array_shift($infos);
// يتم تجاهل كلمة المرور
array_shift($infos);
// يتم إنشاء إدخال في القاموس
$dico[$login] = $infos;
}
// نغلقه
fclose($fic);
// استغلال القاموس
afficheInfos($dico, "login10");
afficheInfos($dico, "X");
// النهاية
exit;
// --------------------------------------------------------------------------
function afficheInfos(array $dico, string $clé): void {
// عرض القيمة المرتبطة بالمفتاح في القاموس $dico إن وجدت
if (isset($dico[$clé])) {
// القيمة موجودة - هل هي مصفوفة؟
$valeur = $dico[$clé];
if (is_array($valeur)) {
print "[$clé," . join(":", $valeur) . "]\n";
} else {
// $valeur ليس مصفوفة
print "[$clé,$valeur]\n";
}
} else {
// $clé ليس مفتاحًا في القاموس $dico
print "la clé [$clé] n'existe pas\n";
}
}
// --------------------------------------------------------------------------
function cutNewLinechar(string $ligne): string {
// يتم حذف علامة نهاية السطر من $ligne إن وجدت
$L = strlen($ligne); // طول السطر
while (substr($ligne, $L - 1, 1) == "\n" or substr($ligne, $L - 1, 1) == "\r") {
$ligne = substr($ligne, 0, $L - 1);
$L--;
}
// النهاية
return($ligne);
}
الملف infos.txt:
النتائج:
[login10,uid10:gid10:infos10:dir10:shell10]
la clé [X] n'existe pas
تعليقات
- السطر 12: fopen(nom_fichier,"w") يفتح الملف nom_fichier للكتابة (w=write). إذا لم يكن الملف موجودًا، يتم إنشاؤه. وإذا كان موجودًا، يتم مسحه. وإذا فشل الإنشاء، فإن fopen تُرجع القيمة false. في العبارة if (!$fic = fopen($INFOS, "w")) {…}، توجد عمليتان متتاليتان: 1) $fic=fopen(..) 2) if( ! $fic) {…} ;
- السطر 18: fputs($fic,$chaîne) يكتب chaîne في الملف $fic. يتم كتابة $chaine مع علامة نهاية السطر \n في نهايته؛
- السطر 21: fclose($fic) يغلق الملف $fic؛
- السطر 26: fopen(nom_fichier,"r") تفتح الملف nom_fichier للقراءة (r=read). إذا فشل فتح الملف (على سبيل المثال، إذا كان الملف غير موجود)، فإن fopen تُرجع القيمة false؛
- السطر 34: fgets($fic,1000) يقرأ السطر التالي من الملف بحد أقصى 1000 حرف. في العملية while ($ligne = fgets($fic, 1000)) {…}، توجد عمليتان متتاليتان: 1) $ligne = fgets(…) 2) while ( ! $ligne). بعد قراءة الحرف الأخير من الملف، تُرجع الدالة fgets القيمة false وتتوقف الحلقة while. تحاول الدالة fgets هنا قراءة ما لا يزيد عن 1000 حرف، لكنها تتوقف فور العثور على علامة نهاية السطر. وبما أن جميع الأسطر هنا تحتوي على أقل من 1000 حرف، فإن الدالة [fgets] تقرأ سطرًا واحدًا من النص، بما في ذلك حرف نهاية السطر. تقوم الدالة cutNewLineChar في الأسطر 75-84 بإزالة أي أحرف نهاية سطر محتملة؛
- السطر 77: تُرجع الدالة strlen($chaîne) عدد أحرف $chaîne؛
- السطر 78: الدالة substr($ligne, $position, $taille) تُرجع $taille حرفًا من $ligne، مأخوذة من الحرف رقم $position، حيث الحرف الأول له الرقم 0. على أجهزة ويندوز، علامة نهاية السطر هي "\r\n". على أجهزة يونكس، هي السلسلة "\n"؛
- السطر 40: تقوم الدالة array_shift($tableau) بإزالة العنصر الأول من $tableau وإرجاعه كنتيجة. يتم هنا تجاهل النتيجة التي ترجعها الدالة array_shift؛
- السطر 62: الدالة is_array($variable) تُرجع true إذا كانت $variable مصفوفة، وإلا تُرجع false؛
- السطر 63: الدالة join تقوم بنفس عمل الدالة implode التي سبق ذكرها؛
3.10. التشفير/فك التشفير jSON

التشفير / فك التشفير jSON (JavaScript Object Notation) هو شيء سنستخدمه بكثرة في التمرين الذي يمثل الخيط الرابط لهذا المستند. تشرح البرامج النصية [json-01.php, json-02.php, json-03.php] ما يجب معرفته للمضي قدماً.
النص البرمجي [json-01.php] هو كما يلي:
<?php
$array1 = ["nom" => "séléné", "prénom" => "bénédicte", "âge" => 34];
// ترميز JSON للمصفوفة array1 مع أحرف Unicode المُهربَة
print "encodage json du tableau array1 avec caractères Unicode échappés\n";
$json1 = json_encode($array1);
print "json1=$json1\n";
// ترميز JSON للمصفوفة array1 بأحرف Unicode غير محولة
print "encodage json du tableau array1 avec caractères Unicode non échappés\n";
$json2 = json_encode($array1, JSON_UNESCAPED_UNICODE);
print "json2=$json2\n";
// فك تشفير jSON في مصفوفة مرتبطة
print "décodage jSON de json2 dans tableau associatif\n";
$array2 = json_decode($json2, true);
var_dump($array2);
foreach ($array2 as $key => $value) {
print "$key:$value\n";
}
// فك تشفير jSON في كائن
print "décodage jSON de json2 dans objet stdClass\n";
$array2 = json_decode($json2);
var_dump($array2);
print "prénom=$array2->prénom\n";
print "nom=$array2->nom\n";
print "âge=$array2->âge\n";
النتائج
تعليقات
- السطر 6 من الكود: تقوم الدالة [json_encode] بتحويل معلمتها إلى سلسلة أحرف jSON؛
- السطر 2 من النتائج: تم إنتاج السلسلة jSON. تم استبدال أحرف Unicode «éâ» برمز Unicode الخاص بها الذي يبدأ بـ \u؛
- السطر 10 من الكود: نكرر نفس العملية، ولكن هذه المرة نطلب الاحتفاظ بأحرف Unicode كما هي؛
- السطر 4 من النتائج: السلسلة الناتجة jSON. وهي أكثر قابلية للقراءة بكثير؛
- الأسطر 14-18 من الكود: نقوم بالعملية العكسية. نحول السلسلة jSON إلى مصفوفة ترابطية؛
- الأسطر 6-13 من النتائج: نرى أننا حصلنا على مصفوفة مرتبطة؛
- الأسطر 19-25 من الكود: نحول سلسلة jSON إلى كائن من النوع [stdClass]؛
- الأسطر 18-25 من النتائج: نلاحظ أنه تم استرداد كائن من النوع [stdClass]؛
- الأسطر 23-25 من الكود: يُرمز للسمة A لكائن O بـ [O→A]؛
يمكن ترميز الجداول متعددة المستويات بتنسيق jSON كما يوضح البرنامج النصي [json-02.php] التالي:
<?php
$array = ["nom" => "séléné", "prénom" => "bénédicte", "âge" => 34,
"mari" => ["nom" => "icariù", "prénom" => "ignacio", "âge" => 35],
"enfants" => [
["prénom" => "angèle", "age" => 8],
["prénom" => "andré", "age" => 2],
]];
// ترميز jSON للمصفوفة متعددة المستويات
print "encodage jSON d'un tableau à plusieurs niveaux\n";
$json = json_encode($array, JSON_UNESCAPED_UNICODE);
print "json=$json\n";
النتائج
encodage jSON d'un tableau à plusieurs niveaux
json={"nom":"séléné","prénom":"bénédicte","âge":34,"mari":{"nom":"icariù","prénom":"ignacio","âge":35},"enfants":[{"prénom":"angèle","age":8},{"prénom":"andré","age":2}]}
تعليقات
في السلسلة jSON:
- تُحاط المصفوفات غير الترابطية بأقواس معقوفة []؛
- المصفوفات المرتبطة محاطة بأقواس معقوفة {}؛
يوضح البرنامج النصي [json-03.php] كيفية استخدام الملف jSON [famille.json] التالي:
{
"épouse": {
"nom": "séléné",
"prénom": "bénédicte",
"âge": 34
},
"mari": {
"nom": "icariù",
"prénom": "ignacio",
"âge": 35
},
"enfants": [
{
"prénom": "angèle",
"age": 8
},
{
"prénom": "andré",
"age": 2
}
]
}
النص البرمجي [json-03.php] هو التالي:
<?php
// قراءة الملف jSON
$json = file_get_contents("famille.json");
// فك تشفير JSON إلى كائن
$famille1 = json_decode($json);
print "----famille1\n";
var_dump($famille1);
// فك تشفير JSON إلى مصفوفة مرتبطة
print "----famille2\n";
$famille2 = json_decode($json, true);
var_dump($famille2);
تعليقات
- السطر 4: تقوم الدالة [file_get_contents] بقراءة محتوى الملف المسمى [famille.json] وتخزينه في المتغير [$json]؛
- ثم يتم فك تشفير المتغير إلى كائن (الأسطر 5-8) وإلى مصفوفة مرتبطة (الأسطر 9-12)؛
النتائج
----famille1
object(stdClass)#2 (3) {
["épouse"]=>
object(stdClass)#1 (3) {
["nom"]=>
string(9) "séléné"
["prénom"]=>
string(11) "bénédicte"
["âge"]=>
int(34)
}
["mari"]=>
object(stdClass)#3 (3) {
["nom"]=>
string(7) "icariù"
["prénom"]=>
string(7) "ignacio"
["âge"]=>
int(35)
}
["enfants"]=>
array(2) {
[0]=>
object(stdClass)#4 (2) {
["prénom"]=>
string(7) "angèle"
["age"]=>
int(8)
}
[1]=>
object(stdClass)#5 (2) {
["prénom"]=>
string(6) "andré"
["age"]=>
int(2)
}
}
}
----famille2
array(3) {
["épouse"]=>
array(3) {
["nom"]=>
string(9) "séléné"
["prénom"]=>
string(11) "bénédicte"
["âge"]=>
int(34)
}
["mari"]=>
array(3) {
["nom"]=>
string(7) "icariù"
["prénom"]=>
string(7) "ignacio"
["âge"]=>
int(35)
}
["enfants"]=>
array(2) {
[0]=>
array(2) {
["prénom"]=>
string(7) "angèle"
["age"]=>
int(8)
}
[1]=>
array(2) {
["prénom"]=>
string(6) "andré"
["age"]=>
int(2)
}
}
}
تعليقات
- الأسطر 1-38: الكائن الناتج عن فك تشفير الملف jSON [famille.json]؛
- الأسطر 39-76: المصفوفة الترابطية الناتجة عن فك تشفير الملف jSON [famille.json]؛