البحث في الموقع
المحتوى عن 'معايير'.
-
وقعتُ أخيرًا بالصدفة على اقتباس من مطور في مشروع Mozilla عن التوتر الكامن في إنشاء المعايير القياسية: ابقِ هذه المقولة في عقلك، ولنشرح كيف أصبحت HTML5 على ما هي عليه. أنواع MIME هذه السّلسلة تتحدث حول HTML5، وليس عن إحدى إصدارات HTML السابقة أو أي إصدارٍ من XHTML، لكن لفهم تاريخ HTML5 والدوافع خلف إنشائها تمامًا، فعليك أن تستوعب بعض التفاصيل التقنية أولًا، تحديدًا أنواع MIME. في كل مرة يطلب فيها متصفح الويب صفحةً، فسيُرسِل الخادوم "ترويسات" (headers) قبل أن يرسل شيفرة الصفحة نفسها، وهذه الترويسات غير ظاهرة عمومًا على الرغم من توفر أدوات تطويرية تمكنك من رؤيتها إن كنت مهتمًا بها. لكن الترويسات مهمة لأنها تُخبر المتصفح كيف يُفسِّر الشيفرات الموجودة في الصفحة، أحد أهم تلك الترويسات هو Content-Type وهو يبدو كما يلي: Content-Type: text/html "text/html" يدعى "Content Type" أو نوع المحتوى أو نوع MIME، هذه الترويسة هي الشيء الوحيد الذي يُحدِّد طبيعة المورد المُحدَّد وكيف يجب عرضه. فالصورة لها أنواع MIME خاصة بها (image/jpeg لصور JPEG، و image/png لصور PNG، وهلمَّ جرًا)؛ ولملفات JavaScript نوع MIME خاص بها، وكذلك الأمر لصفحات الأنماط CSS، فلكل شيء في الويب له نوع MIME خاص به. وبالطبع الواقع معقَّد أكثر من هذا، فالجيل الأول من خواديم الويب (وهنا أتكلم عن خواديم الويب في 1993) لم تكن تُرسِل ترويسة Content-Type لأنها لم تكن موجودةً في ذاك الوقت (إذ لم تُستعمَل إلا في 1994)، وكانت بعض المتصفحات الشهيرة تتجاهل ترويسة Content-Type في بعض الظروف لأسبابٍ لها علاقة بالتوافقية (وهذا يسمى "content sniffing")، لكن كقاعدة عامة، كل شيء يمكنك الحصول عليه على الويب (كصفحات HTML، والصور، والسكربتات، والفيديو، وملفات PDF، وكل شيء له رابط URL) يجب أن يُخدَّم بإضافة نوع MIME المناسب في ترويسة Content-Type. خزِّن المعلومات السابقة في عقلك، وسنعود إليها لاحقًا. شرح مسهب لكيفية إنشاء المعايير لماذا لدينا عنصر <img>؟ لن تسمع مثل هذا السؤال كل يوم. بكل تأكيد أنشأه أحدهم، إذ لم تظهر تلك الأشياء من العدم، فكل عنصر وكل خاصية (attribute) وكل ميزة من ميزات HTML التي استخدمتها من قبل قد أنشأها أحدهم وقرر كيف يجب أن تعمل وكتب كل ذلك، هؤلاء الأشخاص الذين كتبوا المعايير ليسوا خارقين وإنما مجرد بَشَر ولكنهم أذكياء. أحد الأشياء الرائعة عن المعايير هي أنها طُوِّرَت على الملأ، أي أنَّك تستطيع العودة في الزمن والإجابة عن ذاك النوع من الأسئلة؛ إذ أنَّ النقاشات كانت تُجرى في القوائم البريدية، التي أُرشِفَت وأصبحت متاحةً للعموم كي يبحثوا فيها؛ لذلك قررت أن "أنقِّب" في رسائل البريد الإلكتروني كي أحاول الإجابة عن السؤال السابق: "لماذا لدينا عنصر <img>؟"، كان علي البدء في حقبةِ قبل إنشاء منظمة باسم "رابطة الشبكة العالمية" (World Wide Web Consortium اختصارًا W3C)، ذهبت إلى الأيام الأولى للويب، حيث كنتَ تستطيع عدّ صفحات الويب على أصابع اليدين. في 25 شباط/فبراير من عام 1993، كتب Marc Andreessen: كانت صيغتا Xbm و Xpm صيغتَا رسوميات شهيرتان في أنظمة يونكس. "Mosaic" كان من أوائل متصفحات الويب ("X Mosaic" كان الإصدار الذي يعمل على أنظمة يونكس)، عندما كتب Marc Andreessen رسالته في بدايات 1993، لم يكن قد أسس الشركة التي جعلته مشهورًا (شركة Mosaic Communications Corporation)، ولم يكن بدأ العمل على المنتج الرائد في تلك الشركة: "Mosaic Netscape" (ربما تعرفها بأسمائها الحديثة "Netscape Corporation" و "Netscape Navigator"). عبارته "ربما أنواع MIME" كانت تُشير إلى ميزة Content negotiation في HTTP، حيث يُخبر العميل (أي متصفح الويب) الخادوم (أي خادوم الويب) ما هي أنواع الوسائط التي يدعمها (مثل image/jpeg) ومن ثم سيُرسِل الخادوم الوسائط إلى العميل بالصيغة التي يُفضلِّها. عُرِّفَت الصيغة الأصلية من HTTP في 1991 (وهي النسخة الوحيدة التي كانت موجودةً في شباط/فبراير 1993) ولم تكن توفِّر طريقةً للعملاء لأن يخبروا الخواديم ما هي صيغ الصور التي يدعموها، وهذه هي المعضلة التي واجهها Marc. بعد عدِّة ساعات، ردِّ Tony Johnson: Midas هو متصفح آخر من فترة بدايات الويب، وكان منافسًا لمتصفح X Mosaic، وكان متعدد المنصات، إذ كان يعمل على أنظمة يونكس و VMS. أما "SLAC" فهي تُشير إلى Stanford Linear Accelerator Center التي أصبح اسمها الآن "SLAC National Accelerator Laboratory" التي استضافت أول خادوم ويب في الولايات المتحدة (وفي الواقع، أول خادوم ويب خارج أوروبا). عندما كتب Tony هذه الرسالة، كانت SLAC من المحاربين القدامى في الشبكة العالمية، التي استضافت خمس صفحات على خادوم الويب الخاص بها لمدة 441 يومًا. أكمل Tony قائلًا: قصد ببروتوكول "HTTP2" بروتوكول HTTP الأساسي المُعرِّف في 1992، الذي لم يُطبَّق تطبيقًا كاملًا في بدايات 1993، وعُرِفَت المسودة باسم HTTP2 ثم أصبحت معيارًا قياسيًا باسم "HTTP 1.0" (بالرّغم من أن الأمر قد تم ذلك بعد ثلاثة أعوام)، تضمَّن بروتوكول HTTP 1.0 ترويسات طلبات لتحديد صيغة المحتوى (request headers for content negotiation)، أي أنواع MIME. أكمل Tony: لم يُطبَّق اقتراحه أبدًا، إلا أنَّ فكرة توفير نص إن لم تتوفر الصورة هي تقنية مهمة لتسهيل الوصول التي كانت ناقصة من اقتراح Marc الأولي لوسم <IMG>. استعملت هذه الميزة في خاصية <img alt>، التي أساء متصفح Netscape معاملتها باعتبارها تلميحًا (tooltip). بعد عدِّة ساعات من إرسال Tony لرسالته، ردَّ Tim Berners-Lee عليها: لم يُطبَّق هذا الاقتراح مطلقًا، لكن خاصية rel ما زالت موجودةً. أضاف Jim Davis: لم يُطبَّق هذا الاقتراح قط، لكن أضاف متصفح Netscape لاحقًا دعمًا لتضمين عناصر الوسائط المتعددة باستعمال عنصر <embed>. سأل Jay C. Weber: ردَّ Marc Andreessen: أجاب Jay C. Weber له قائلًا: أدركنا بعد فوات الأوان أنَّ مخاوف Jay كان لها أساسٌ من الصحة لكن ذلك استغرق فترةً طويلةً، فقد أضافت HTML5 أخيرًا عنصرَيّ <video> و <audio>. ردًا على رسالة Jay الأصلية، قال Dave Raggett: لاحقًا في 1993، اقترح Dave Raggett معيار HTML+ الذي كان تطويرًا لمعيار HTML. لكن لم يُطبَّق اقتراحه مطلقًا، ثم حلَّت HTML 2.0 محله التي أعطت طابعًا رسميًا للميزات شائعة الاستعمال: "هذا المعيار يضفي توضيحًا وطابعًا رسميًا لمجموعة من ميزات HTML التي كانت شائعة الاستعمال قبل حزيران/يونيو عام 1994". كتب Dave لاحقًا معيار HTML 3.0 المبني على مسودة HTML+ التي كتبها سابقًا، وذلك خارج إطار W3C للمعايير (المسمى Arena)؛ لكن لم تُطبَّق HTML 3.0 أبدًا، وحلَّت محلها HTML 3.2، التي رسَّمَت الميزات كالإصدار السابق HTML 2.0: "أضافت HTML 3.2 الميزات شائعة الاستخدام مثل الجداول، و applets والتفاف النص حول الصور، بالإضافة إلى توافقيتها مع معيار HTML 2.0". شارك Dave لاحقًا بوضع معيار HTML 4.0، وطوَّر HTML Tidy، وشارك في المساعدة بتطوير XHTML، و XForms، و MathML، وغيرها من معايير W3C الحديثة. بالعودة إلى 1993، رد Marc على Dave: Intermedia هو مشروعٌ من جامعة Brown، طوِّر من عام 1985 إلى 1991 وكان يعمل على نظام A/UX، الذي هو نظام شبيه بِيونكس (Unix-like) لحواسيب ماكنتوش في ذاك الوقت. راجت فكرة "لغة لتوصيفِ الرسومات ذاتُ غرضٍ عام"، وذلك بدعم المتصفحات الحديثة لصيغة SVG (لغة توصيفية يمكن دمج السكربتات معها)، و <canvas> (واجهة برمجية [API] إجرائية [procedural] مباشرة)، على الرغم من أن الأخيرة بدأت كإضافة مملوكة (proprietary extension) قبل أن يتم ترسيمُها من WHATGW. ردBill Janssen: "Andrew" هو إشارة إلى Andrew User Interface System (إلا أنه كان يسمى في ذاك الوقت Andrew Project). في ذاك الحين، وجد Thomas Fine فكرةً مختلفةً: "Display Postscript" هي تقنية لعرض Postscript على الشاشة طوِّرَتها كل من Adobe و NeXT. لم يُطبَّق هذا الاقتراح أبدًا، لكن الفكرة أنَّ أفضل طريقة لحل مشاكل HTML هي استبدال شيءٍ ما آخر بها ما زالت تظهر من وقتٍ لآخر. قال Tim Berners-Lee في الثاني من آذار/مارس عام 1993: HyTime كان نظام مستندات قديم مبني على SGML، وقد أثَّرَ كثيرًا في النقاشات الأولية للغة HTML، ولاحقًا لغة XML. لم يُطبَّق اقتراح Tim لوسم <INCLUDE> مطلقًا، لكنك تجده صداه واضحًا في عناصر <object> و <embed> و <iframe>. في النهاية، قال Marc Andreessen في الثاني عشر من آذار/مارس عام 1993: ترجمة -وبتصرّف- لفصل A Quite Biased History of HTML5 من كتاب Dive Into HTML5 لمؤلفه Mark Pilgrim. اقرأ أيضًا المقال التالي: نظرة على تاريخ HTML - الجزء الثاني المقال السابق: خمسة أشياء عليك معرفتها عن HTML5 النسخة الكملة لكتاب نحو فهم أعمق لتقنيات HTML5
-
هل أنت من محاربي PHP القدامى وتريد معرفة ما الذي استجد منذ عدِّة سنوات؟ أم أنت منتقلٌ حديثًا إلى PHP من لغةٍ أخرى وتود معرفة الأمور المثيرة في PHP، ها قد وصلت إلى المكان الصحيح. لننفض الغبار عن معلوماتك، وتهيّأ أن تتعلم ميزاتٍ أضيفت حديثًا إلى PHP. معايير PHP-FIG أعداد مشاريع ومكتبات وأطر عمل PHP الموجودة حاليًا مهولة، إذ هنالك العديد من أطر عمل PHP المتوفرة للاستعمال، لكن من الصعب استعمالها معًا، فماذا لو استطاع أحد أطر العمل الاستفادة من مكتبة ما خارجية، بدلًا من كتابتها يدويًا، أو الاستفادة من مكتبة من إطار Laravel مثلًا؟ لهذا الغرض أُنشِئت PHP-FIG (اختصار للعبارة Framework Interoperability Group) في مؤتمر php|tek في 2009ـ التي وضعت عدِّة معايير يُرمَز لها بالاختصار PSR (أي PHP Standards Recommendations) سنورد ذكرها هنا باختصار. PSR-1: معيار كتابة الشيفرات يوضح هذا المعيار الأمور الأساسية التي يجب أخذها بعين الاعتبار عند كتابة الشيفرات لتحقيق أكبر قدر من المحمولية وإمكانية التشغيل مع بقية المكتبات والبرمجيات. يجب استعمال وسوم <?php ?> الاعتيادية، ووسم echo المختصر <?= ?> فقط. يجب أن يكون ترميز ملفات الشيفرات UTF-8 دون BOM. يجب على الملف أن يُنشِئ بنى برمجية جديدة مثل الأصناف (classes) والدوال …إلخ. دون أن يُحدِث أي "تأثير جانبي"، أو يجب أن ينفِّذ الخطوات المنطقية التي تؤدي إلى "تأثيرات جانبية" ولكن لا يُسمَح أن يقوم بكلا الأمرين. نستطيع تعريف "التأثيرات الجانبية" بالأمور غير المتعلقة بتعريف الأصناف أو الدوال، وهي تشمل: توليد المخرجات، أو تضمين الملفات (عبر include أو require)، أو الاتصال إلى الخدمات الخارجية، أو تعديل ضبط ini، أو تعديل المتغيرات العامة أو الكتابة إلى ملفات، وهلم جرًا. يجب أن تكون مجالات الأسماء (namespaces) وأسماء الأصناف متوافقة مع معيار PSR-4 (سنأتي على ذكره بعد قليل)، وهذا يعني أن كل ملف سيحتوي على صنف وحيد باسمه، وفي مجال أسماء من مرحلة (level) واحدة على الأقل. يجب أن تكون أسماء الأصناف على الشكل StudlyCaps (أي الحرف الأول من كل كلمة كبير). يجب أن تكون الثوابت المُعرَّفة في الأصناف بأحرف كبيرة وتفصل الشرطة السفلية بين الكلمات. يجب أن تكون أسماء الدوال على الشكل camelCase (أي الحرف الأول من كل كلمة كبير، عدا أول كلمة). PSR-2: معيار تنسيق الشيفرات يساعد هذا المعيار في تسهيل التعامل مع الملفات التي كتبها مبرمجون آخرون عبر تحديد قواعد مشتركة لكيفية تنسيق شيفرات PHP. يعتمد هذا المعيار على المعيار PSR-1، أي على المبرمج تطبيق قواعد PSR-1 أولًا. يجب أن تُستعمل أربعة فراغات (مسافات) لمحاذاة الشيفرات، وليست مسافات الجدولة (tabs)، ولا يجوز أن تدمج بين الطريقتين، وذلك لتفادي حدوث مشاكل في ملفات الفروقات (diff) وغيرها. ليس هنالك حدٌ أقصى لعدد المحارف في السطر، لكن يستحسن أن يكون بطول 80 محرف أو أقل، ويمكن إضافة أسطر فارغة لتحسين مقروئية النص. ولا يجوز وضع أكثر من تعبير برمجي في السطر الواحد. يجب أن تكون الكلمات المفتاحية (keywords) في PHP بأحرفٍ صغيرة، وكذلك الأمر للثوابت true و false و null. يجب وجود سطر فارغ وحيد بعد تعريف مجال الأسماء (namespace)، وكذلك الأمر بعد use. يجب أن يكون قوس البداية لصنف أو دالة في سطرٍ منفصل، وكذلك قوس النهاية؛ ولا يجوز وضع فراغ بين اسم الدالة وقوس المعاملات، ويجب وضع فراغ وحيد بعد الفاصلة "," في حال وجود أكثر من معامل. يجب تعيين مُحدِّد وصول مثل public أو private أو protected، وعدم استخدام var. يجب وضع فراغ وحيد بعد الكلمة المحجوزة لبنى التحكم (مثل if و for وغيرهما). PSR-3: معيار السجلات يُعرِّف هذا المعيار واجهةً (interface) للتسجيل (logging). PSR-4: معيار التحميل التلقائي شرحنا التحميل التلقائي في درس توزيع شيفرات PHP على عدة ملفات، يمكنك العودة إليه لمزيدٍ من المعلومات. الحزم البرمجية تخيل معي الوضع التالي: أنت مُطور PHP، لديك مشروع تود تطويره، قد تختار إطار عمل مُعين لهذه المهمة، لكنك ستحتاج إلى بضعة مكتبات إضافية للقيام بذلك، تخيل بأنك تود أن يقوم تطبيقك بنشر تحديثات مُعينة على حساب المُستخدم على تويتر، وجدت المكتبة التي ترغب في استخدامها لكنها مكتبة تعتمد على مكتبة أخرى. مُطور PHP من العصر الحجري سيقوم بالتالي: سيقوم بتحميل نُسخة من إطار العمل، ومن ثم يقوم بإنشاء مُجلد يضع فيه المكتبات الإضافية التي يحتاجها ومن ثم يُحاول فهم آلية عملها ليربطها ببعضها البعض. قد تؤتي هذه الطريقة أكلها، وقد تسمح لك بتطوير مشروعك "من دون أية مشاكل"، لكن ماذا يحدث مثلا لو تم إطلاق تحديث لأي من المكتبات التي تعتمد عليها؟ هل ستقوم بإعادة تحميلها من جديد واستبدال الإصدار القديم بالجديد؟ هل يُمكن أن تفعل ذلك لو كنت تستخدم أكثر من مكتبة يعتمد بعضها على بعض؟ لست متأكدا من ذلك. لكن ما هو البديل؟ هل عرفت فائدة أدوات إدارة الحزم؟ ما رأيك أن تكمل قراءة مقال ما هو Composer ولماذا يجب على كل مطور PHP استخدامه وتتعرف على composer وتتعلم طريقة استخدامه. كلمات المرور توجد قابلية تسجيل مستخدمين جدد في أغلبية المواقع، وهذا يعني أنَّ على المستخدم توفير كلمة مرور لكي يدخل على حسابه، لكن هل تساءلت من قبل عن أكثر الطرق أمانًا في تخزين كلمات مرور المستخدمين؟ سأنصحك بعض النصائح في هذا الصدد. لا يجدر بك معرفة كلمات مرور مستخدميك هذا يعني أنَّك ستخزِّن كلمة المرور على شكل نص بسيط في مكانٍ ما في قاعدة بياناتك، افترض مثلًا أنَّ موقعك قد تعرض للاختراق، واستطاع المُخترَق الوصول إلى قاعدة بيانات موقعك واستطاع رؤية جميع كلمات مرور مستخدميك! أنت تعرض سلامة حسابات مستخدميك الأخرى (وسمعة موقعك) للخطر. لا ترسل كلمات المرور الجديدة عبر البريد الإلكتروني هذا خطأٌ كبيرٌ لأنه يعني أنَّ الموقع يعلم كلمة مرور المستخدم، ولقد أرسلها عبر خدمة البريد (قد لا يكون الاتصال مشفرًا!)؛ وإنما عليك إرسال رابط سيسمح للمستخدم بكتابة كلمة مرور جديدة. لا تشفر (encrypt) كلمات المرور قد تظن أنَّ التشفير فكرةٌ جيدةٌ لكن تذكر أنَّ العملية قابلة للعكس، فأي شخص يملك وصولًا إلى شيفرات موقعك البرمجية سيقدر على تحويل كلمات المرور المُشفَّرة إلى أصلها. لا تستخدم MD5 من الجيد أن تستعمل طريقة تحويل غير قابلة للعكس، فهذه الطرق -مثل MD5- غير قابلة للعكس، مما يُصعِّب مهمة معرفة كلمة المرور الأصلية؛ وإذا أردت التأكد أنَّ كلمة المرور التي أدخلها المستخدم مطابقة لكلمة المرور المخزنة في قاعدة البيانات، فعليك أولًا تحويل كلمة المرور التي أدخلها بإحدى الطرق ثم مقارنتها مع الكلمة المخزنة في قاعدة البيانات. لكن يَسهُل كثيرًا توليد جداول بالقيم الأصلية والقيم المحوَّلة تسمى "جداول rainbow"، وسيتم البحث عن القيم المحولة إلى أن يُعثَر على تطابق (ينطبق المثل على SHA-1). أتت PHP 5.5 بدوال بسيطة لتحويل كلمات المرور بأمان وهي password_hash() و password_verify(). تُستعمل الدالة الأولى لتحويل كلمة المرور إلى عبارة غير قابلة للعكس التي تستطيع تخزينها بأمان في قاعدة بياناتك. $hash = password_hash($password, PASSWORD_DEFAULT); هذا كل ما في الأمر: أول وسيط هو كلمة المرور التي تريد تحويلها، والوسيط الثاني هو الخوارزمية التي تريد استخدامها للتحويل. الخوارزمية الافتراضية هي bcrypt، ويجب أن تُخزِّن القيم الناتجة في حقل أكبر من 60 محرف في قاعدة البيانات (ربما تستعمل 255). يمكنك أيضًا تمرير PASSWORD_BCRYPT كوسيط في حال أردت أن يكون الناتج بطول 60 محرف دومًا. أما دالة password_verify() فهي تقارن كلمة المرور التي أدخلها المستخدم (الوسيط الأول) بكلمة المرور المحوَّلة والمخزنة في قاعدة البيانات (الوسيط الثاني). <?php if (password_verify($password, $hash)) { // كلمة المرور صحيحة } else { // كلمة المرور غير مطابقة } الأخطاء في PHP أكثر ما يواجهه المبرمج في حياته هو الأخطاء! نحاول -نحن معشر المبرمجين- أن نتلافى حدوث الأخطاء، لكن ذلك ليس ممكنًا في الحياة العملية. علينا أن نعي أنَّ هنالك تصنيفين: الأول هو الأخطاء (errors) التي رأيتها سابقًا خلال هذه السلسلة، التي تُظهِرها الدوال المُضمَّنة في اللغة؛ والثاني هو الاستثناءات (exceptions) التي تظهر في البرامج التي تعتمد على البرمجة غرضية التوجه. تُصنَّف PHP على أنها لا تعتمد كثيرًا على الاستثناءات، وإنما تعتمد على الأخطاء. فلو حاولت مثلًا أن تطبع قيمة متغير غير معرف، فستظهر تنبيهًا لكن PHP ستكمل تفسير السكربت: $ php -a php > echo $foo; Notice: Undefined variable: foo in php shell code on line 1 أما في اللغات الأخرى التي تعتمد اعتمادًا كاملًا على الاستثناء -مثل بايثون- فستختلف النتيجة: $ python print foo Traceback (most recent call last): File “”, line 1, in NameError: name ‘foo’ is not defined التبليغ عن الأخطاء في PHP هنالك مستويات مختلفة من التبليغ عن الأخطاء في PHP، أشهر ثلاثة مستويات هي الأخطاء (errors) والتنبيهات (notices) والتحذيرات (warning). الأخطاء (errors) هي المشاكل التي تظهر في وقت التشغيل (run-time) التي يكون سببها مشاكل في الشيفرة وستسبب توقف التنفيذ. أما التنبيهات فهي رسائل إرشادية التي قد تسبب مشاكل أثناء تنفيذ السكربت، لكن التنفيذ لن يتوقف. أما التحذيرات فهي شبيهة بالأخطاء لكنها لن توقف عمل السكربت. تستطيع تغيير السلوك الافتراضي للتبليغ عن الأخطاء عبر الدالة error_reporting() التي تستطيع تستطيع ضبط مستوى التبليغ عن الأخطاء أثناء التنفيذ بتمرير ثابت من الثوابت المُعرَّفة مسبقًا لمستويات الأخطاء (E_ERRORللأخطاء، E_NOTICE للتنبيهات، E_WARNING للتحذيرات). فلو كنت تريد مشاهدة الأخطاء والتحذيرات لكنك لا تريد التنبيهات، فيمكنك ضبط ذلك كالآتي: <?php error_reporting(E_ERROR | E_WARNING); تستطيع أن تخبر PHP أن تتجاهل الأخطاء في عبارة برمجية معيّنة باستخدام معامل التحكم بالأخطاء @. يمكنك وضع هذا المعامل قبل تعبير برمجي، وسيتم تجاهل أيّة أخطاء يُسبِّبها هذا التعبير. <?php echo @$foo['bar']; المثال السابق سيطبع قيمة $foo['bar'] إن كانت موجودةً، لكنه لن يطبع شيئًا إن لم يكن المتغير $foo أو المفتاح 'bar' موجودًا؛ فدون وجود معامل التحكم بالأخطاء، كان سيظهر أحد التنبيهين: PHP Notice: Undefined variable: foo أو PHP Notice: Undefined index: bar. بالطبع يمكنك استخدام العبارة الآتية لتنجب وضع معامل تجاهل الأخطاء: <?php echo isset($foo['bar']) ? $foo['bar'] : ''; الاستثناءات تمثِّل الاستثناءات جزءًا مهمًا من العديد من لغات البرمجة مثل ruby أو java، فأي شيء يحدث بشكل خاطئ في تلك اللغات -مثل فشل طلبية HTTP أو فشل الاتصال بقاعدة البيانات- فسيُرمَى (throw) استثناء يعني أنَّ هنالك خطأٌ ما. لكن PHP نفسها متساهلة جدًا بهذا الأمر، فلو فشل استدعاء الدالة file_get_contents() فستحصل على FALSE وربما رسالة تحذيرية (أي من المستوى E_WARNING)؛ أما أطر العمل الحديثة، فتستعمل الاستثناءات. تبنى آلية معالجة الأخطاء في PHP على وضع التعبيرات البرمجية في كتلة try التي تريد مراقبتها من أجل الأخطاء، فلو حدث استثناءٌ ما داخل كتلة try (تحدث الاستثناءات عند "رميها" [throw]) فسيُلتَقَط باستخدام catch التي تلي كتلة try التي رمت الاستثناء. أنا متأكدٌ أنَّك تتساءل عن معنى ما سبق. ما رأيك أن نأخذ مثالًا توضيحيًا يساعد على الفهم: <?php try { $num = 10; if ($num < 20) { throw new Exception("Exception here!"); } $foo = "bar"; } catch(Exception $exception) { print "Exception!\n"; } ?> دخل مُفسِّر PHP إلى كتلة try وبدأ تنفيذ الشيفرة، وعند وصوله إلى السطر throw new Exception توقف عن تنفيذ كتلة try وانتقل إلى كتلة catch؛ لاحظ أنَّه عندما "يغادر" مُفسِّر PHP كتلة try فلن يعود إليها مطلقًا، أي أنَّ السطر $foo = "bar" لن يُنفَّذ. قد ترى أنَّ كتلة catch معقدة في بادئ الأمر، لكنني سأريك مثلًا يعتمد على أنَّ مفسر PHP سينتقل إلى كتلة catch المناسبة، لكن علي أولًا شرح التعبير (catch(Exception $exception. نُحدِّد في كتلة catch أنَّ الصنف هو Exception لأنَّ على PHP أن تُحدِّد أي كتلة من كتل catch يجب تنفيذها بالبحث عن الصنف الموافق للصنف الذي رُميَ. أو بالأحرى، تُجري PHP عملية instanceof (هل تذكرها من درس البرمجة كائنية التوجه؟) وهذا يعني أنَّ على الاستثناء الذي رُميَ أن يكون من الصنف المُحدَّد أو من صنف مشتق منه (أعلم تمامًا العلم أنَّ ما سبق يبدو معقدًا، لكنه أبسط بكثير مما تظن). لاحظ أنَّ جميع الاستثناءات مشتقة من الصنف Exception الذي يوفِّر وظائف أساسية، وأغلبية الدوال الموجودة في الصنف Exception هي final أي لا يمكن إعادة كتابتها في الأصناف المشتقة. يمكنك مثلًا استدعاء الدالة $exception->getMessage() لمعرفة رسالة الخطأ ("Exception here!" في المثال السابق)، أو يمكنك استدعاء getFile() لمعرفة الملف الذي رمى الاستثناء. هذا المثال يوضِّح الشرح السابق: <?php class ExceptFoo extends Exception { } class ExceptBar extends ExceptFoo { } try { $foo = "bar"; throw new ExceptFoo("Baaaaad PHP!"); $bar = "baz"; } catch (ExceptFoo $exception) { echo "Caught ExceptFoo\n"; echo "Message: {$exception->getMessage()}\n"; } catch (ExceptBar $exception) { echo "Caught ExceptBar\n"; echo "Message: {$exception->getMessage()}\n"; } catch (Exception $exception) { echo "Caught Exception\n"; echo "Message: {$exception->getMessage()}\n"; } ?> ناتج السكربت السابق: Caught ExceptFoo Message: Baaaaad PHP! هذا منطقي لأننا رمينا استثناء من الصنف ExceptionFoo، ولهذا ستنتقل PHP إلى كتلة catch. جرب الآن هذه الشيفرة: <?php class ExceptFoo extends Exception { } class ExceptBar extends ExceptFoo { } try { $foo = "bar"; throw new ExceptBar("Baaaaad PHP!"); $bar = "baz"; } catch (ExceptFoo $exception) { echo "Caught ExceptFoo\n"; echo "Message: {$exception->getMessage()}\n"; } catch (ExceptBar $exception) { echo "Caught ExceptBar\n"; echo "Message: {$exception->getMessage()}\n"; } catch (Exception $exception) { echo "Caught Exception\n"; echo "Message: {$exception->getMessage()}\n"; } ?> لماذا ناتج الشيفرة السابقة مماثلة لما قبلها؟ لأنَّ PHP تنتقل إلى أول كتلة catch مُطابِقة لصنف الاستثناء أو أيّة أصناف أب له؛ ولما كان ExceptionBar مشتقٌ من ExceptionFoo، وكانت كتلة catch التابع للصنف ExceptionFoo تأتي قبل ExceptionBar، فستنفَّذ كتلة ExceptionFoo. يمكنك إعادة كتابة الشيفرة كالآتي لتفادي هذه الإشكالية: <?php class ExceptFoo extends Exception { } class ExceptBar extends ExceptFoo { } try { $foo = "bar"; throw new ExceptBar("Baaaaad PHP!"); $bar = "baz"; } catch (ExceptBar $exception) { echo "Caught ExceptBar\n"; echo "Message: {$exception->getMessage()}\n"; } catch (ExceptFoo $exception) { echo "Caught ExceptFoo\n"; echo "Message: {$exception->getMessage()}\n"; } catch (Exception $exception) { echo "Caught Exception\n"; echo "Message: {$exception->getMessage()}\n"; } ?> بقي أمرٌ بسيطٌ تجدر الإشارة إليه ألا وهو كتلة finally الموجودة في إصدار PHP 5.5 وما بعده، التي تضمن لك تنفيذ الشيفرات البرمجية الموجودة فيها دائمًا حتى لو حدث استثناءٌ ما. <?php try { complicatedCode(); } catch (NastyException $e) { handleError($e); } finally { importantCleanup(); } ?> المولدات Generators هذه ميزةٌ جديدةٌ في PHP منذ الإصدار 5.5، وهي تسمح لك باستعمال حلقة foreach للمرور على مجموعة من البيانات دون الحاجة إلى إنشاء مصفوفة في الذاكرة، الأمر الذي قد يؤدي إلى تجاوز حد استهلاك الذاكرة المسموح، أو إلى وقت معالجة كبير… إذ تستطيع كتابة دالة مولدة (generator function) التي تشبه الدوال العادية، إلا أنها بدلًا من إعادة قيمة ما، فهي "تُنتِج" (yield) قيمًا لكي يتم المرور عليها باستعمال الحلقات. مثالٌ بسيطٌ عنها هو دالة range(0, 1000000) التي تولد مصفوفة فيها قيم عددية من الصفر إلى المليون، وستستهلك 100 ميغابايت من الذاكرة العشوائية. ونستطيع بدلًا من ذلك أن نكتب مولدة اسمها xrange() -على سبيل المثال- وستستهلك أقل من 1 كيلوبايت! <?php function xrange($start, $limit) { for ($i = $start; $i <= $limit; $i++) { // استعملنا yield بدلًا من return yield $i; } } // استعملنا المصفوفة المُعادة من استدعاء الدالة range في foreach كالمعتاد foreach (range(1, 9) as $number) { echo "$number "; } echo "\n"; // وكذلك استعملنا نواتج المولدة xrange foreach (xrange(1, 9) as $number) { echo "$number "; } ?> الفرق بين الطريقتين في استهلاك الذاكرة فقط، ولا تأثير لها على سرعة التنفيذ. المصادر راجع صفحة Basic Coding Standard و Coding Style Guide و Logger Interface و Autoloading Standard، وتابع الجديد عبر موقع PHP-FIG. راجع مقالة ما هو Composer ولماذا يجب على كل مطور PHP استخدامه لصاحبها يوغرطة بن علي. لمزيد من المعلومات حول تحويل كلمات المرور، راجع صفحة password_hash و password_verify في دليل PHP، وهذا السؤال على stack overflow. انظر إلى قسم الاستثناءات في PHP: The Right Way، ومقالة Exception handling، وصفحة Exceptions في دليل PHP. تعلم المزيد عن المولدات عبر دليل PHP بصفحتيه Generators overview و Generator syntax.