اذهب إلى المحتوى

لوحة المتصدرين

  1. يوغرطة بن علي

    يوغرطة بن علي

    الأعضاء


    • نقاط

      1

    • المساهمات

      125


  2. عبد اللطيف ايمش

    • نقاط

      1

    • المساهمات

      1406


  3. محمد أحمد العيل

    • نقاط

      1

    • المساهمات

      308


  4. ماجد محمد5

    ماجد محمد5

    الأعضاء


    • نقاط

      1

    • المساهمات

      1


المحتوى الأكثر حصولًا على سمعة جيدة

المحتوى الأعلى تقييمًا في 10/29/17 في كل الموقع

  1. تخيل معي الوضع التالي: أنت مُطور PHP، لديك مشروع تود تطويره، قد تختار إطار عمل مُعين لهذه المهمة، لكنك ستحتاج إلى بضعة مكتبات إضافية للقيام بذلك، تخيل بأنك تود أن يقوم تطبيقك بنشر تحديثات مُعينة على حساب المُستخدم على تويتر، وجدت المكتبة التي ترغب في استخدامها لكنها مكتبة تعتمد على مكتبة أخرى. مُطور PHP من العصر الحجري سيقوم بالتالي: سيقوم بتحميل نُسخة من إطار العمل، ومن ثم يقوم بإنشاء مُجلد يضع فيه المكتبات الإضافية التي يحتاجها ومن ثم يُحاول فهم آلية عملها ليربطها ببعضها البعض. قد تؤتي هذه الطريقة أكلها، وقد تسمح لك بتطوير مشروعك "من دون أية مشاكل"، لكن ماذا يحدث مثلا لو تم إطلاق تحديث لأي من المكتبات التي تعتمد عليها؟ هل ستقوم بإعادة تحميلها من جديد واستبدال الإصدار القديم بالجديد؟ هل يُمكن أن تفعل ذلك لو كنت تستخدم أكثر من مكتبة يعتمد بعضها على بعض؟ لست متأكدا من ذلك. لكن ما هو البديل؟ إن سبق لك أن استخدمت لُغات برمجة أخرى كـ javascript مع node.js أو ruby فإنه سبق لك أن تعاملت مع ما يُطلق عليه اسم مدير الحزم Package manager، حيث يتم استخدام npm مع node مثلا لتنصيب حزم وإضافات لـ node. يُمكن القول بأن موضع composer من PHP هو موضع npm من node.js، حيث يُتيح composer تحميل المكتبات التي تحتاجها في مشروعك والإبقاء عليها مُحدثة دون الحاجة إلى تحميلها ونقلها يدويا. رغم كل ذلك يُشير موقع composer الرسمي بأنه لا يُمكن أن نُطلق عليه اسم مُدير حزم بحكم أنه لا يقوم بتنصيب هذه الحزم بشكل عام على النظام global بل تتم إدارة الحزم داخل كل مشروع بشكل محلي، ولهذا يُطلق عليه وصف مُدير الاعتمادات Dependency Manager. تنصيب composer دعونا من الجانب النظري ولنقم بتنصيب composer ولنلق نظرة على كيفية استخدامه. بالرغم من أنه يُمكن تنصيبه بشكل محلي داخل كل مشروع إلا أنه يُفضل تنصيبه بشكل عام على النظام. على أنظمة Linux/Unix يكفي تنفيذ الأمرين التاليين لتنصيب composer: $ curl -sS https://getcomposer.org/installer | php $ mv composer.phar /usr/local/bin/composer قد تحتاج إلى إضافة sudo قبل الأمر الثاني إن احتجت إلى صلاحيات مدير النظام لتنفيذ الأمر. أما على أنظمة Windows فيكفي تحميل وتنصيب التطبيق الرسمي الخاص به. يُمكنك التحقق من إذا ما تم تنصيب composer بشكل صحيح على النظام بتنفيذ أمر composer في سطر الأوامر والذي من شأنه أن يُظهر المساعدة الخاصة به. استخدام Composer الآن وبعد أن قمنا بتنصيب composer سنحتاج إلى إنشاء ملف composer.json نقوم من خلاله بإعلام composer بالحزم التي نود إرفاقها والاعتماد عليها في مشروعنا الجديد، كما أنه يُمكن لهذا الملف أن يحتوي على بيانات أخرى سنحتاجها في بناء المشروع. يكون ملف composer.json في شكله الأبسط على النحو التالي: { "require": { "monolog/monolog": "1.0.*" } } في هذا المثال فإننا نعتمد على الإصدار 1.0.* من مكتبة monolog . بطبيعة الحال يُمكن الاعتماد على أكثر من مكتبة في مشروعنا الحالي، حيث يكفي إضافة سطر جديد لكل مكتبة ما بين حاضنتي require ويتكون كل سطر من اسم المكتبة (الذي عادة ما يحتوي على اسم الجهة المُنتجة لها متبوعة باسمها، وعادة ما يكون نفس الاسم مُكررا مرتين) إضافة إلى رقم الإصدار الذي نرغب فيه. يُمكن إيجاد هذه المكتبات وآليات إضافتها إلى مشروعك الخاص بالبحث على موقع https://packagist.org/. الآن وبعد أن حددنا المكتبات التي نرغب فيها يكفي أن نقوم بتنفيذ الأمر composer install أو php composer.phar install في حال ما إذا لم تقم بنقل composer.phar إلى مُجلد مساره موجود في مُتغير PATH الخاص بالنظام. سيقوم composer بتحميل جميع تلك المكتبات ووضعها داخل مُجلد vendor الذي سيتم إنشاؤه داخل مُجلد المشروع الحالي. Autoloading ولتجنيب المُطور من اللجوء إلى استدعاء هذه المكتبات واحدة واحدة لدى كتابته لمشروعه، يقوم composer بإنشاء ملف vendors/autoloader.php الذي يتولى إدارة ذلك حيث يكفي استدعاء هذا الملف لتتمكن من استخدام المكتبات التي حملتها من دون الحاجة إلى القيام بذلك يدويا: <?php require_once "vendors/autoloader.php"; تحديث المكتبات لدى صدور تحديث جديد للمكتبة التي تعتمد عليها فإنه يكفي تنفيذ الأمر للحصول عليها: composer update بطبيعة الحال إن كنت قد حددت إصدارا مُعينا في ملف composer.json فإنك لن تحصل على الإصدارات الأحدث ما لم تقم بتحديد الإصدار بشكل يسمح بالترقية الآلية. بعبارة أخرى إذا كنت تستعمل مثلا إطار عمل Laravel وقمت بإضافته باستخدام السطر التاليينlaravel/framework": "4.1.* فإنه سيتم التحديث إلى إصدار في التفرع 4.1 ولن يتم المرور إلى الإصدارات 4.2 أو التي تليها. Packagist Packagist عبارة عن موقع يتم تجميع فيه مكتبات PHP مفتوحة المصدر المتوفر للاستعمال من طرف الجميع باستخدام composer. حسب التوثيق الرسمي لـ composer فإنه لا يُشترط في المكتبة أن تكون على Packagist ليتم استدعاؤها من طرف Composer إلا أنه يُفضل إن أردت توفير مكتبتك للجميع أن تُسجلها على هذا الموقع. خلاصة إن كنت مُطور PHP وكنت تود أن تتطور مع تطور هذه اللغة وأن لا تبقى حبيس الإصدارات القديمة منها (الإصدار 4؟) فإنه يجب عليك أن تتبع أسلوبا مُختلفا في التطوير عن أسلوب مُطور PHP من العصر الحجري. من بين أولى الخطوات التي ستخطوها للوصول إلى ذلك هو الاستعانة بـ composer في جميع مشاريعك التي تعمل عليها حيث يُعتبر الغراء الذي يُلصق مُكونات مشروعك بعضها ببعض ويُسهل عليك مهمة التطوير. للمزيد حول composer وحول مُختلف المكتبات التي يُمكن الاستعانة بها في مشروعك قم بزيارة موقعه الرسمي وموقع Packagist.
    1 نقطة
  2. اشتهر استخدام منصة Heroku السحابية ضمن مجتمع مطوري Ruby on Rails ونالت فيه شعبية واسعة؛ إلا أن الخدمة لم تقتصر على مطوري Ruby وما يدور حولها بل تجاوزتهم إلى تقديم الدعم للغات برمجة مثل Node.js ،Java و PHP؛ من بين أخرى. توفّر Heroku خطّة اشتراك مجانية يمكن استخدامها لإدارة مشاريع صغيرة جدا أو لأغراض الاختبار. سنشرح في هذا الدرس كيفية الاستفادة من Heroku عبر هذه الخطة لنشر Deploying تطبيقات Laravel. إنشاء حساب على Heroku يجب أولا أن ننشئ حسابا على موقع الخدمة حتى يمكننا الاستفادة منها. التسجيل مجاني ولا يستغرق سوى دقائق. ستُعرَض عليك خلال عملية التسجيل خيارات للغة البرمجة التي تريد استخدامها، اختر PHP؛ مع العلم أن هذا الخيار لا يؤثّر على إمكانية استعمالك للغات برمجة أخرى مستقبلا. تثبيت Heroku Toolbelt الخطوة الثانية بعد إنشاء الحساب هي تثبيت أداة Heroku Toolbelt. تُستخدَم هذه الأداة، التي تعمل عبر سطر الأوامر، لإدارة جوانب عدّة من المشاريع المضافة إلى Heroku؛ ومن ضمنها إدارة عمليّة النشر، تهجير Migrating قاعدة البيانات والتخاطب مع خادوم Heroku. تتوفّر الأداة على وندوز، ماك وتوزيعة أوبونتو لينكس. نفّذ بعد تثبيت الأداة الأمر التالي: $ heroku login heroku-cli: Installing CLI... 21.83MB/21.83MB Enter your Heroku credentials. Email: mail@example.com Password (typing will be hidden): Logged in as mail@example.com انتظر قليلا حتى يكتمل تنزيل عميل Heroku ثمّ أدخل معلومات الاستيثاق الخاصّة بك (عنوان البريد وكلمة السر). نشر تطبيق Laravel على Heroku يمكننا الآن بعد التسجيل في Heroku وتثبيت الأداة Heroku Toolbelt نشرُ مشروع Laravel. نبدأ بإنشاء مشروع Laravel جديد (على الحاسوب الشخصي): $ composer create-project laravel/laravel dev.herokutest.com dev-develop Installing laravel/laravel (dev-develop 083db95...dac46617) - Installing laravel/laravel (dev-develop develop) Cloning develop ... Compiling views Do you want to remove the existing VCS (.git, .svn..) history? [Y,n]? Y Application key [9UCBk7IDjvAGrkLOUBXw43yYKlymlqE3Y] set successfully. ثم ننشئ ملفا باسم Procfile ونضعه في المجلد الجذر لمشروع Laravel. طريقة كتابة اسم الملفّ مهمة جدا (الحرف الأول كبير، ولا وجود لامتداد للملف). يقرأ Heroku هذا الملفّ لتحديد نوع العمليات التي سيجريها بعد نشر التطبيق. في حالة تطبيق Laravel فإن نوع العمليات المطلوب هو وِب web. نحدّد نوع خادوم الوِب المستخدم لتقديم التطبيق (Apache) والمجلّد الذي توجد به ملفات التطبيق المخصّصة للعرض، وهو في حالة Laravel المجلد public. يصبح ملفّ Procfile على النحو التالي: web: vendor/bin/heroku-php-apache2 public هذا فقط مثال على الخيارات المتاحة، يمكنك تغيير هذه الخيارات (خادوم الوِب مثلا) إن أردت ذلك. الخطوة الموالية لإنشاء ملفّ Procfile هي وضع المشروع تحت تصرّف نظام إدارة الإصدارات Git بإنشاء مستودع للمشروع: $ git init Initialized empty Git repository in /home/zeine77/dev.herokutest.com/.git/ $ git add . $ git commit -m "First commit" يسهّل استخدامُ Git كثيرا عمليةَ النشر، فإطار العمل Laravel يأتي مبدئيا بميزات خاصّة بنظام إدارة الإصدارات Git (مثل ملفات gitignore.)؛ كما أن Heroku أيضا يتفاعل مع مستودع Git المحلي لتسهيل النشر. راجع هذه المقالات لمعرفة المزيد عن Git. نحن الآن جاهزون لنشر التطبيق على Heroku. نستخدم Heroku Toolbelt لهذه المهمة: $ heroku create Heroku CLI submits usage information back to Heroku. If you would like to disable this, set `skip_analytics: true` in /home/zeine77/.heroku/config.json Creating app... done, ⬢ nameless-chamber-90421 https://nameless-chamber-90421.herokuapp.com/ | https://git.heroku.com/nameless-chamber-90421.git ينشئ الأمر heroku create اسما جديدا لمشروعك (أعطاني الاسم nameless-chamber-90421) ويعرّف رابطا يمكن عبره الوصول إلى التطبيق. لا يوجد على الرابط - لحد السّاعة - سوى صفحة مبدئية من Heroku. زيادة على الرابط والاسم، أنشأ الأمر السابق مستودع Git بعيدا. مستودع Git بعيد هو مستودع يضم ملفات مشروعك ولكنه يوجد في مكان آخر غير جهازك؛ يمكن دفع التغييرات إلى المشروع البعيد أو جلبها منه. سنكتفي في حالة Heroku بدفع التعديلات إلى المستودع البعيد، كما سنرى بعد قليل. يستخدم Heroku ملفات تسمى buildpacks (حزم بناء) لمعرفة البرامج التي يجب عليه إعدادها على الخادوم بعد تثبيت التطبيق؛ لذا يجب أن نحدّد واحدا. اخترنا ملفّ buildpack الرسمي من Heroku الخاص بتطبيقات PHP؛ نستخدم الأمر config:add في Heroku Toolbelt لتحديد هذا الملف: $ heroku config:add BUILDPACK_URL=https://github.com/heroku/heroku-buildpack-php Setting BUILDPACK_URL and restarting ⬢ nameless-chamber-90421... done, v3 BUILDPACK_URL: https://github.com/heroku/heroku-buildpack-php تستخدم تطبيقات Laravel مفتاح تعميّة Encryption key لتعمية معلومات جلسة المستخدم ومعلومات أخرى؛ توجد قيمة هذا المفتاح في متغيّر البيئة APP_KEY. يوجد المتغيّر APP_KEY في الملفّ env.، إلا أن الملف env. لا يدخل في إطار الملفات التي يتعامل معها Git، نظرا لوجوده في الملفات المحدّدة في gitignore.. سنحتاج إذن لتوليد مفتاح تعميّة لاستخدامه على خادوم Heroku. تُستخدم أداة artisan لتوليد مفتاح تعمية على النحو التالي: php artisan key:generate --show يولّد الأمر أعلاه مفتاح تعميّة ويعرضه على سطر الأوامر؛ إلا أننا نريد أن نخزّن المفتاح على الخادوم؛ نستخدم Toolbelt لهذا الغرض على النحو التالي: heroku config:set APP_KEY=$(php artisan --no-ansi key:generate --show) Setting APP_KEY and restarting ⬢ nameless-chamber-90421... done, v7 APP_KEY: base64:jp40IC7SV5eJ5IhjQYwqk/KXJG0uS+ZhCqSGwkwgELs= يضبط الأمر السابق قيمة المتغيّر APP_KEY على الخادوم لتساوي نتيجة تنفيذ الأمر php artisan --no-ansi key:generate --show. حان الآن وقت النشر فعليا؛ ندفع التغييرات في المستودع المحلي إلى المستودع البعيد باستخدام Git على النحو التالي: $ git push heroku master Counting objects: 103, done. Delta compression using up to 4 threads. Compressing objects: 100% (84/84), done. Writing objects: 100% (103/103), 43.87 KiB | 0 bytes/s, done. Total 103 (delta 5), reused 0 (delta 0) remote: Compressing source files... done. remote: Building source: remote: remote: -----> Fetching set buildpack https://github.com/heroku/heroku-buildpack-php... done remote: -----> PHP app detected remote: remote: ! WARNING: Your 'composer.json' contains a non-'stable' setting remote: for 'minimum-stability'. This may cause the installation of remote: unstable versions of runtimes and extensions during this deploy. remote: It is recommended that you always use stability flags instead, remote: even if you have 'prefer-stable' enabled. For more information, remote: see https://getcomposer.org/doc/01-basic-usage.md#stability remote: remote: -----> Bootstrapping... remote: -----> Installing platform packages... remote: - php (7.0.7) remote: - ext-mbstring (bundled with php) remote: - apache (2.4.20) remote: - nginx (1.8.1) remote: -----> Installing dependencies. (...) remote: -----> Compressing... remote: Done: 15.5M remote: -----> Launching... remote: Released v4 remote: https://nameless-chamber-90421.herokuapp.com/ deployed to Heroku remote: remote: Verifying deploy... done. To https://git.heroku.com/nameless-chamber-90421.git * [new branch] master -> master إن نظرت إلى لوحة التحكّم في Heroku ستجد سجلا بالإجراءات السابقة. هذا كلّ ما في الأمر؛ اكتمل نشرُ تطبيقك الآن ويمكنك الوصول إليه على الرابط المذكور أعلاه. يجب أن تظهر صفحة Laravel المبدئية. تذكّر أن الرابط المنشَأ سابقا موجود فقط لأغراض الاختبار والتجربة، عندما يكون تطبيقك جاهزا لتلقي الجماهير يمكنك استخدام نطاقك الخاص وربطه بالتطبيق. تهجير قاعدة البيانات نشرنا في الخطوات السابقة تطبيق Laravel جديدا؛ إلا أن هذه الخطوات لن تكون كافية إن كان التطبيق يعتمد على قاعدة بيانات. ستحتاج في هذه الحالة إلى التأكد من تنفيذ جميع التهجيرات العالقة بعد كلّ عملية نشر. بما أن التطبيق جديد على Heroku فسنحتاج لتموين Provision قاعدة البيانات؛ نستخدم Toolbelt لهذا الغرض: $ heroku addons:create heroku-postgresql:hobby-dev Creating postgresql-rigid-59415... done, (free) Adding postgresql-rigid-59415 to nameless-chamber-90421... done Setting DATABASE_URL and restarting nameless-chamber-90421... done, v10 Database has been created and is available ! This database is empty. If upgrading, you can transfer ! data from another database with pg:copy Use `heroku addons:docs heroku-postgresql` to view documentation. ينشئ الأمر السابق قاعدة بيانات PostgreSQL معرّفة بالخطة المجانيّة hobby-dev التي تمكننا من إنشاء قاعدة بيانات مجانية على Heroku، على ألا يتجاوز عدد أسطرها العشرة آلاف. توجد خطط أخرى يمكن النظر فيها لإيجاد ما يناسبك إن كنت تريد استخدام Heroku بيئةً للإنتاج. يعود السبب في اختيارنا لقاعدة بيانات PostgreSQL بدلا من MySQL إلى أن دعم الأخيرة على Heroku محدود، ستجد لهذا السبب أن الكثير من التوثيق حول خدمة Heroku يعتمد على قاعدة البيانات PostgreSQL. ثم نفذ الأمر التالي للحصول على المزيد من التفاصيل عن قاعدة البيانات ومن ضمنها الاستيثاق (تأكد من اسم التطبيق): $ heroku config --app nameless-chamber-90421 | grep DATABASE_URL DATABASE_URL: postgres://USERNAME:PASSWORD@HOSTNAME:PORT/DATABASE يظهر في نتيجة الأمر اسمُ المستخدم USERNAME، كلمة السّر PASSWORD، اسم المضيف HOSTNAME، المنفذ PORT واسم قاعدة البيانات DATABASE. لن يكون ضروريا حفظ هذه الإعدادات فالمتغير DATABASE_URL الذي يخزّنها محفوظ تلقائيا في إعدادات الخادوم. يمكنك تسهيل إدارة قاعدتي البيانات على طرفيْ العمل (بيئة التطوير وبيئة الإنتاج) بضبط متغيّر بيئة باسم DATABASE_URL على جهازك المحلي وتخزين إعدادات قاعدة البيانات فيه ثم استخدامه لإعداد اتصال Laravel بقاعدة البيانات. ستحتاج لتثبيت PostgreSQL على جهازك إن لم يكن مثبتا مسبقا. يستعمل Laravel مبدئيا قاعدة بيانات MySQL، لذا يجب أن نعدّه لاستخدام PostgreSQL. نفتح ملفّ إعداد الاتصال بقاعدة البيانات config/database.php ونبحث عن السطر التالي: 'default' => env('DB_CONNECTION', 'mysql'), ثم نعدّله على النحو التالي: 'default' => env('DB_CONNECTION', 'pgsql'), ثم ننتقل إلى المقطع الخاصّ بإعداد PostgreSQL ضمن ملفّ إعداد الاتصال ونعدّله ليصبح كالتالي: 'pgsql' => [ 'driver' => 'pgsql', 'host' => parse_url(getenv("DATABASE_URL"))["host"], 'database' => substr(parse_url(getenv("DATABASE_URL"))["path"], 1), 'username' => parse_url(getenv("DATABASE_URL"))["user"], 'password' => parse_url(getenv("DATABASE_URL"))["pass"], 'charset' => 'utf8', 'prefix' => '', 'schema' => 'public', ], احفظ التعديلات ثم تأكد من أن اتصال التطبيق بقاعدة البيانات (محليّا)؛ يمكنك إنشاء نموذج في Laravel وتهجير مرافق له لغرض اختبار الاتصال بقاعدة البيانات. نفذ بعد التأكد من إعداد قاعدة البيانات التعديلات التي أضفتها إلى منطقة الإدارج في Git ثم أودعها في المستودع وأرسلها إلى المستودع البعيد على الخادوم: $ git add . $ git commit -m "Updated database configuration" $ git push heroku master يمكنك الآن تنفيذ التهجير على قاعدة البيانات على الخادوم عن طريق Toolbelt كالتالي: $ heroku run php artisan migrate --app nameless-chamber-90421 Running `php artisan migrate` attached to terminal... up, run.6981 ************************************** * Application In Production! * ************************************** Do you really wish to run this command? [y/N] y Migration table created successfully. Migrated: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_100000_create_password_resets_table Migrated: 2015_01_30_032004_create_todolists_table.php ترجمة -وبتصرّف- للمقال Deploying a Laravel Application to Heroku لصاحبه W. Jason Gilmore.
    1 نقطة
  3. وضع Netscape’s Brendan Eich أسس جافا سكريبت سنة 1995. وكان الغرض منها أن تكون لغة ترميز سهلة خاصة بالمواقع ومكملة للجافا في تطبيقات الويب المعقدة، ولكن سهولة دمج جافا سكريبت والدعم الذاتي لها مع المتصفحات جعلها أكثر شيوعًا من لغة الجافا الأصلية في واجهات الويب. لا يقتصر استخدام جافا سكريبت مقتصرة على المتصفحات، ف Node.js مشروع قائم بذاته ويقدم إمكانية بناء تطبيقات إنترنت قائمة بذاتها. صيغة الشفرة البرمجية الخاصة بجافا سكريبت شبيهة بطريقة كتابة لغة C، فإذا كنت قد تعاملت مع لغة البرمجة C قبل ذلك أو جافا، ستكون الكثير من الأساسيات مألوفة لك. على الرغم من ذلك، وعلى الرغم من سهولة الاسم، إلا أن النموذج الكائني في جافا سكريبت مختلف تماماً عن الموجود في الجافا. سنتناول في هذا المقال المواضيع التالية: التعليقات. الأرقام، النصوص والعمليات. المتغيرات، المصفوفات والكائنات. جمل التحكم والمنطق. الدوال، نطاق الوصول و Closures. المشيّدات Constructors والنماذج الأولية Prototypes التعليقات لكتابة تعليق من سطر واحد نبدأ السطر بعلامتي / كما في السطر التالي: // Single-line comments start with two slashes. لكتابة تعليق من أكثر من سطر، نستخدم /* و */ في إحاطة الأسطر التي نريدها كما في الأسطر التالية: /* Multiline comments start with slash-star، and end with star-slash */ تنتهي الجمل في جافا سكريبت بفاصلة منقوطة، ولكن هذا الأمر غير ضروري، حيث يتم إضافة الفاصلة المنقوطة تلقائيا عند وجود سطر جديد وعدم وجود الفاصلة، وهذا الأمر مستثنى في بعض الحالات: doStuff(); بدون فاصلة: doStuff() سنعتمد في هذا الدرس استخدام الفاصلة المنقوطة. دورة تطوير التطبيقات باستخدام لغة JavaScript تعلم البرمجة بلغة جافا سكريبت انطلاقًا من أبسط المفاهيم وحتى بناء تطبيقات حقيقية. اشترك الآن الأرقام، النصوص والعمليات تحتوي جافا سكريبت على نوع رقمي واحد (64-bit IEEE 754 double). الأرقام من نوع Double (الأعداد الحقيقة) تحتوي على 52 بت من الأساس العشري، بما يكفي لتخزين الأعداد الصحيحة Integers حتى 9✕10¹⁵ بدقة. 3; // = 3 1.5; // = 1.5 بعض العمليات الحسابية الأساسية: 1 + 1; // = 2 0.1 + 0.2; // = 0.30000000000000004 8 - 1; // = 7 10 * 2; // = 20 35 / 5; // = 7 5 / 2; // = 2.5 10 % 2; // = 0 30 % 4; // = 2 18.5 % 7; // = 4.5 العمليات الثنائية متاحة أيضا، فعند إجراءك لعملية ثنائية، فإن الأعداد العشرية Float يتم تحويله إلى أعداد طبيعية Int حتى 32 بت: 1 << 2; // = 4 ترتيب العمليات يتم بواسطة استخدام الأقواس: (1 + 3) * 2; // = 8 توجد ثلاثة قيم أرقام غير حقيقية كالتالي: Infinity; // ناتجة عن قسمة رقم موجب على صفر -Infinity; // ناتجة عن قسمة رقم سالب على صفر NaN; //تشير إلى قيمة "غير رقم" القيم المنطقية: true; false; يتم استخدام علامة التنصيص المنفردة أو المزدوجة لبناء النصوص: 'abc'; "Hello، world"; لعكس القيمة نستخدم علامة التعجب: !true; // = false !false; // = true لفحص المساواة: 1 === 1; // = true 2 === 1; // = false لفحص عدم المساواة: 1 !== 1; // = false 2 !== 1; // = true عمليات المقارنة: 1 < 10; // = true 1 > 10; // = false 2 <= 2; // = true 2 >= 2; // = true دمج النصوص يتم بواسطة عملية + : "Hello " + "world!"; // = "Hello world!" وعملية الدمج + لا تعمل فقط مع النصوص، بل مع الأرقام أيضا والتراكيب مثل المصفوفات: "1، 2، " + 3; // = "1، 2، 3" "Hello " + ["world"، "!"] // = "Hello world،!" من الممكن مقارنة النصوص: "a" < "b"; // = true لإجراء عملية فحص المساواة باعتبار تحويل أنواع البيانات (في حالة اختلافها) نستخدم عملية = مرتين: "5" == 5; // = true null == undefined; // = true في حالة استخدام = ثلاثة مرات، لا تتم عملية التحويل: "5" === 5; // = false null === undefined; // = false لابد من الانتباه من التحويل التلقائي للنوع تجنبا لبعض الحالات غير المرغوبة: 13 + !0; // 14 "13" + !0; // '13true' نستخدم charAt للوصول لمحرف Character معين في النصوص بتعيين مكانها في سلسلة المحارف: "This is a string".charAt(0); // = 'T' أو نستخدم substring للحصول على أجزاء أكبر من النصوص: "Hello world".substring(0, 5); // = "Hello" length تعتبر خاصية، لذلك لا تستخدم الأقواس في النهاية: "Hello".length; // = 5 نستخدم null للإشارة للفارغ أو غير الموجود، بينما نستخدم undefined للإشارة لقيمة غير منشأة أو غير موجودة حاليا (مثل تعريف متغير وعدم إعطائه قيمة). القيم false، null، undefined، NaN، 0 ،”” كلها قيم خاطئة (تستخدم كقيمة منطقية خطأ) والباقي صحيح. المتغيرات، المصفوفات، والكائنات يتم تعريف المتغيرات باستخدام كلمة var. جافا سكريبت ديناميكية النوع، حيث لا يجب عليك تحديد نوع المتغير عند تعريفه، ولإعطاء قيمة للمتغير نستخدم = كما في المثال التالي: var someVar = 5; عند عدم استخدام كلمة var لن يظهر لك خطأ، ولكن في هذه الحالة فإن المتغير يكون مستواه على نطاق الوصول العام Global scope ولن يكون على المستوى الذي تم تعريفه فقط. someOtherVar = 10; المتغيرات التي لا تأخذ قيمة عند تعريفها تكون بقيمة undefined تلقائيا: var someThirdVar; // = undefined لتعريف أكثر من متغير في نفس السطر نفصل بين المتغيرات بفاصلة عادية: var someFourthVar = 2، someFifthVar = 4; نستطيع اختصار كتابة العمليات الحسابية بالشكل التالي: someVar += 5; // هذا يعادل someVar = someVar + 5; someVar is 10 now someVar *= 10; // someVar = 100 someVar++; // someVar = 101 someVar--; // back = 100 المصفوفات عبارة عن قائمة من القيم المرتبة من أي نوع: var myArray = ["Hello"، 45، true]; نستطيع الوصول لمحتويات المصفوفة باستخدام الأقواس المعكوفة والفهرس. فهرس المصفوفات يبدأ من صفر: myArray[1]; // = 45 المصفوفات غير ثابتة وذات حجم متغير: myArray.push("World"); myArray.length; // = 4 للتعديل أو الإضافة في موقع معين في المصفوفة: myArray[3] = "Hello"; لتعريف قاموس (Hash): var myObj = {key1: "Hello"، key2: "World"}; المفاتيح في القاموس عبارة عن نص، أو مُعرف صحيح، والقيم تأخذ أي نوع: var myObj = {myKey: "myValue"، "my other key": 4}; للوصول إلى قيمة باستخدام مفتاح والأقواس المعكوفة: myObj["my other key"]; // = 4 أو باستخدام صيغة النقطة والمُعِرف الذي يمثل المفتاح: myObj.myKey; // = "myValue" الكائنات في جافا سكريبت غير ثابتة وقابلة للتعديل: myObj.myThirdKey = true; إذا حاولت الوصول لقيمة غير موجودة في القاموس، ستكون النتيجة المرجعة undefined: myObj.myFourthKey; // = undefined جمل التحكم والمنطق جملة if: var count = 1; if (count == 3){ // ستُنفَّذ هذه الشفرةإذا كانت قيمة المتغير تساوي 3 } else if (count == 4){ // ستُنفَّذ هذه الشفرةإذا كانت قيمة المتغير تساوي 4 } else { // ستُنفَّذ هذه الشفرة في حالة عدم تحقق أي شرط سابق } جملة while: while (true){ // جملة تكرار غير منتهية } جملة do تشبه جملة while إلا أنها تُكرَّر مرة واحدة على الأقل: var input; do { input = getInput(); } while (!isValid(input)) جملة For تشبه الموجودة في لغة سي وجافا: for (var i = 0; i < 5; i++){ // ستُنفَّذ هذه الشفرة خمس مرات } توقف جملة التكرار باستخدام break مع تحديد اسم جملة التكرار التي نريد وقفها: outer: for (var i = 0; i < 10; i++) { for (var j = 0; j < 10; j++) { if (i == 5 && j ==5) { break outer; } } } تسمح لنا جملة for/in بالمرور على خصائص ومحتويات الكائن. في المثال التالي نقوم بالمرور على محتوى قاموس وحفظ النتيجة في متغير: var description = ""; var person = {fname:"Paul"، lname:"Ken"، age:18}; for (var x in person){ description += person[x] + " "; } // description = 'Paul Ken 18 ' العملية المنطقية and تُمَثَلْ ب && والعملية or تُمَثَلْ ب ||: if (house.size == "big" && house.colour == "blue"){ house.contains = "bear"; } if (colour == "red" || colour == "blue"){ // colour is either red or blue } نستفيد من && و || في تحديد القيم التلقائية كما في المثال التالي: var name = otherName || "default"; جملة switch تفحص المساواة باستخدام ===، استخدم break بعد كل حالة فحص وإلا سيتم تنفيذ حالة case الصحيحة التالية أيضا: grade = 'B'; switch (grade) { case 'A': console.log("Great job"); break; case 'B': console.log("OK job"); break; case 'C': console.log("You can do better"); break; default: console.log("Oy vey"); break; } الدوال، نطاق الوصول وClosures تُعرَّف الدوال في جافا سكريبت باستخدام كلمة function: function myFunction(thing){ return thing.toUpperCase(); } myFunction("foo"); // = "FOO" لابد الانتباه أن تضع القيمة المرجعة في نفس السطر الموجودة به كلمة return، إذا لم يكن كذلك، ستكون النتيجة المرجعة undefined بسبب الإضافة التلقائية للفاصلة المنقوطة عند كل سطر جديد (وقد نوهنا لهذه النقطة في البداية). function myFunction(){ return // الفاصلة المنقوطة مضافة تلقائيا هنا {thisIsAn: 'object literal'} } myFunction(); // = undefined يُتعامل مع الدوال في جافا سكريبت بوصفها كائنات، وهذا يعني أنك تستطيع تمرير الدالة معاملا لدالة أخرى، أو قيمة لمتغير. تُستخدَم الدالة myFunction في معالجة حدث في المثال التالي، حيث سيتم تنفيذها بعد فترة زمنية محددة: function myFunction(){ } // ينتُج عن السطر التالي تنفيذ الدالة أعلاه بعد 5 ثوان setTimeout(myFunction، 5000); ملاحظة: الدالة setTimeout ليست جزءًا من جافا سكريبت، ولكنها مقدمة من قبل المتصفحات و Node.js. وظيفة setInterval أيضا مقدمة من قبل المتصفحات. function myFunction(){ } setInterval(myFunction، 5000); ليس من الشرط تحديد اسم الدالة، ونستطيع كتابة الدالة دون اسم في المكان الذي يتم تمرير قيمتها المُرجعة فيه بالطريقة التالية: setTimeout(function(){ }, 5000); تمتلك جافا سكريبت نطاقاً وظيفياً، حيث لكل دالة نطاقها الخاص، بينما الكتل الأخرى لا تشاركها هذا النطاق. if (true){ var i = 5; } i; // = 5 إن كتبنا الشفرة في المثال السابق داخل دالة فإن قيمة المتغير i تساوي 5 على عكس ما تتوقعه في النطاق الكتلي، بمعنى أن المتغيرات مُشاهدَة ونستطيع الوصول إليها على مستوى الدالة بغض النظر عن مكان تعريفها داخل هذه الدالة. وهذا يشير إلى نمط متعارف عليه يمنع المتغيرات المؤقتة من الظهور في نطاق الوصول العام. وللتوضيح على ما سبق، في المثال التالي، يبقى المتغير temporary داخل نطاق الدالة المُعرف فيها، أما المتغيرات في النطاق العام مثل permanent فنستطيع الوصول إليه باستخدام الكائن العام والمسمى في كل المتصفحات ب window وتكون صيغة الوصول للمتغير هكذا window.permanent. الكائن ذو النطاق العام يختلف اسمه في البيئات التي لا علاقة لها بالمتصفحات مثل Node.js. (function(){ var temporary = 5; window.permanent = 10; })(); temporary; // raises ReferenceError permanent; // = 10 من أقوى خصائص لغة جافا سكريبت وجود ما يسمى بclosures ، حيث إذا كانت دالة مُعرفة داخل دالة أخرى، فإن الدالة الداخلية تمتلك الوصول لكافة المتغيرات الخاصة بالدالة الخارجية حتى بعد خروجها وانتهائها. في المثال التالي، فإن استدعاء الدالة setTimeout سيتم تنفيذها مباشرة بعد استدعاء الدالة الخارجية sayHelloInFiveSeconds والتي ستنتهي مباشرة. ومن ثم سوف يبدأ العد حتى 5 ثوان لاستدعاء الوظيفة الداخلية، وعند انتهاء المدة، وعلى الرغم من خروج وانتهاء الدالة الخارجية، إلا أنه سيتم تنفيذ الداخلية بنجاح وسيتم الوصول للمتغير prompt دون مشاكل. function sayHelloInFiveSeconds(name){ var prompt = "Hello، " + name + "!"; function inner(){ alert(prompt); } setTimeout(inner، 5000); } // سيتم طباعة "مرحبا أدم" بعد 5 ثواني sayHelloInFiveSeconds("Adam"); المشيّدات Constructors والنماذج الأولية Prototypes يمكن للكائنات أن تحتوي على دوال، كما في المثال التالي: var myObj = { myFunc: function(){ return "Hello world!"; } }; myObj.myFunc(); // = "Hello world!" عندما يتم استدعاء دوال معرَّفة في كائن، فإن هذه الدوال تستطيع الوصول للكائن التي عُرِّفت فيه باستخدام كلمة this كما في المثال التالي: myObj = { myString: "Hello world!"، myFunc: function(){ return this.myString; } }; myObj.myFunc(); // = "Hello world!" الدالة myFunc لا تعمل إذا لم يتم استدعاؤها في سياق الكائن الذي تتصل به، لاحظ في المثال التالي: var myFunc = myObj.myFunc; myFunc(); // = undefined نستطيع ربط دالة بكائن والوصول لمتغيرات هذا الكائن بواسطة this على الرغم من أن هذه الدالة لم تُعرَّف مع تعريف بالكائن. var myOtherFunc = function(){ return this.myString.toUpperCase(); } myObj.myOtherFunc = myOtherFunc; myObj.myOtherFunc(); // = "HELLO WORLD!" نستطيع أيضا تحديد سياق الدالة لتنفيذها من خلاله وذلك عن طريق استدعاء الوظيفة باستخدام call او apply. var anotherFunc = function(s){ return this.myString + s; } anotherFunc.call(myObj، " And Hello Moon!"); // = "Hello World! And Hello Moon!" استخدمنا في المثال السابق الدالة call. تؤدّي الدالة apply نفس الغرض ولكننا نمرر لها مصفوفة معاملات، وهذا يفيدنا في حالة التعامل مع دالة تقبل مجموعة من المعاملات. anotherFunc.apply(myObj، [" And Hello Sun!"]); // = "Hello World! And Hello Sun!" Math.min(42، 6، 27); // = 6 Math.min([42، 6، 27]); // = NaN (uh-oh!) Math.min.apply(Math، [42، 6، 27]); // = 6 لاحظ أننا عند استخدام apply و call قمنا بتمرير السياق الذي نريده من خلال myObj. إذا أردنا أن نُثبت السياق الذي نريد تنفيذ الدالة من خلاله، فإننا نستخدم bind عوضا عن ذلك. var boundFunc = anotherFunc.bind(myObj); boundFunc(" And Hello Saturn!"); // = "Hello World! And Hello Saturn!" نستطيع استخدام bind لتطبيق دالة جزئيا، انظر المثال التالي: var product = function(a، b){ return a * b; } var doubler = product.bind(this، 2); doubler(8); // = 16 عند استدعاء دالة بواسطة الكلمة new فإن كائناً جديداً يتم إنشاؤه وسوف يكون متاحا للدالة بواسطة كلمة this. الدوال التي صُممت للاستدعاء بهذه الطريقة تسمى المشيّدات constructors. var MyConstructor = function(){ this.myNumber = 5; } myNewObj = new MyConstructor(); // = {myNumber: 5} myNewObj.myNumber; // = 5 على خلاف لغات البرمجة الكائنية الأخرى، جافا سكريبت لا تحتوي على مفهوم العيّنة Instance أو “الكائن المتولد من الفئة عند التشغيل”. تُقدم جافا سكريبت المفاهيم الكائنية مثل التوليد والوراثة من خلال مفهوم واحد يسمى النموذج الأولي Prototype. كل كائن في الجافا سكريبت يحتوي على نموذج أولي. عندما تقوم بمحاولة استخدام لخاصية غير موجودة في كائن معين، فإن مفسر جافا سكريبت سوف ينظر في النموذج الأولي للكائن. تجعلك بعض تطبيقات الجافا سكريبت تصل لنموذج الكائن بواسطة الخاصية “proto“. على الرغم من أن هذه الطريقة مفيدة في شرح مفهوم النموذج الأولي، إلا أنها ليست الطريقة المعيارية لذلك، وسوف نشرح الطريقة الصحيحة لهذا الأمر لاحقا. var myObj = { myString: "Hello world!" }; var myPrototype = { meaningOfLife: 42، myFunc: function(){ return this.myString.toLowerCase() } }; myObj.__proto__ = myPrototype; myObj.meaningOfLife; // = 42 myObj.myFunc(); // = "hello world!" في حال لم تكن الخاصية موجودة في النموذج الأولي، فإن المفسر يبحث في نموذج النموذج وهكذا. myPrototype.__proto__ = { myBoolean: true }; myObj.myBoolean; // = true لا يوجد نُسَخْ عند استخدام النموذج، حيث إن كل كائن يقوم بالتأشير للنموذج الخاص به، وهذا يعني أن أي تغيير على النموذج سوف ينعكس في كل مكان آخر. myPrototype.meaningOfLife = 43; myObj.meaningOfLife; // = 43 جملة for/in تسمح بالمرور على خصائص كائن، مرورا بسلسلة النماذج الأولية حتى الوصول إلى نموذج فارغ. for (var x in myObj){ console.log(myObj[x]); } ///prints: // Hello world! // 42 // [Function: myFunc] للمرور على خصائص الكائن دون النموذج، نستخدم وظيفة hasOwnProperty كما في المثال التالي: for (var x in myObj){ if (myObj.hasOwnProperty(x)){ console.log(myObj[x]); } } ///prints: // Hello world! كما ذكرنا سابقا، فإن استخدام “proto” في تعريف نموذج كائن هي طريقة غير معيارية، ولا يوجد طريقة لتغيير نموذج أولي لكائن موجود. على الرغم من ذلك، توجد طريقتان لإنشاء كائن مع نموذج مُعطى. الأولى هي استخدام Object.create: var myObj = Object.create(myPrototype); myObj.meaningOfLife; // = 43 الطريقة الثانية – مضمونة أكثر - باستخدام المشيّدات. تمتلك المشيّدات خاصية تسمى prototype تُحدَّد عند إنشاء كائن جدي باستخدام كلمة new، المثال التالي يشرح هذا الأمر: MyConstructor.prototype = { myNumber: 5، getMyNumber: function(){ return this.myNumber; } }; var myNewObj2 = new MyConstructor(); myNewObj2.getMyNumber(); // = 5 myNewObj2.myNumber = 6 myNewObj2.getMyNumber(); // = 6 توجد لدى أنواع البيانات مثل النصوص والأرقام مشيّدات تقوم بإنشاء كائنات تعادل الكائنات المنشأة بطريقة عادية. عدا أنها ليست متماثلة تماما! var myNumber = 12; var myNumberObj = new Number(12); myNumber == myNumberObj; // = true typeof myNumber; // = 'number' typeof myNumberObj; // = 'object' myNumber === myNumberObj; // = false if (0){ //لن تُنفَّذ هذه الشفرة لأن قيمة الصفر خاطئة } if (new Number(0)){ //سوف تُنفَّذ هذه الشفرة لأن الرقم في الشرط عبارة عن كائن وليس نوع رقم، والكائنات دائما ذات قيمة منطقية صحيحة } الكائنات المغلفة أو العادية تتشارك في النموذج الأولي الخاص بنوعها، فمثلا، نستطيع إضافة خاصية على النموذج الخاص بنوع string بهدف الحصول على الحرف الأول من النص، كما في المثال التالي: String.prototype.firstCharacter = function(){ return this.charAt(0); } "abc".firstCharacter(); // = "a" تُستخدَم الخاصية السابقة غالباً في ما يُعرَف بالملْء المتعدّد Polyfilling والتي تُطَبِقْ مميزات أحدث من جافا سكريبت في مجموعة قديمة من نُسخ جافا سكريبت بهدف استخدام هذه المميزات الحديثة في بيئات قديمة مثل المتصفحات المنتهية تاريخا. ملاحظة: تنفيذ Object.create قد يكون غير متاح في بعض التطبيقات، ولكننا نستطيع استخدام الملْء المتعدّد لتعويض هذا الغياب كالتالي: if (Object.create === undefined){ //في حالة كانت موجودة لا تعدل عليها Object.create = function(proto){ // أنشئ مشيّدًا مؤقتا باستخدام النموذج الأولي المناسب var Constructor = function(){}; Constructor.prototype = proto; return new Constructor(); } } ترجمة – بتصرّف – للمقال Learn X in Y minutes Where X=javascript.
    1 نقطة
  4. هل أنت من محاربي 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.
    1 نقطة
×
×
  • أضف...