نحن في Badoo ننتقل بنشاط إلى PHP 7.4 ونحن متحمسون جدًا لفرصة استخدام وظيفة التحميل المسبق الجديدة. منذ وقت ليس ببعيد
تحدثنا عن تجاربنا معها.
على ما يبدو ، فإن المجتمع متحمس كما نحن.
يناقش مطورو الإطار بنشاط إمكانية تقديم التحميل المسبق (وقد
قدم البعض بالفعل
دعمه ). الآن جاء دور مدير التبعية لـ Composer.

كتب
إيتالو بايزا مقالًا أعرب فيه عن رأيه حول كيفية عمل الملحن مع التحميل المسبق. قررت مشاركة ترجمة لهذا النص ، وفي الوقت نفسه ترجمة
لمقاله الآخر ، حول كيفية استجابة مطوري الملحن أنفسهم للمقترح ، وكذلك حول أداة جديدة تجعل العمل مع التحميل المسبق أسهل.
كيف يجب تحميل الملحن في PHP 7.4
التحميل المسبق هو إحدى الميزات المهمة التي يوفرها PHP 7.4 للمطورين الذين يحتاجون إلى أداء أفضل. يمكن تسمية هذه الوظيفة "الاحماء" قبل تنفيذ محرك JIT ، الذي سيظهر (أو يجب أن يظهر) في PHP 8. قبل ذلك ، سيكون التحميل المسبق كافياً ، ومن يدري ، ربما يمكنهم العمل بالترادف.
ما وظيفة التحميل المسبق موضحة في
هذه المقالة . خلاصة القول بسيطة للغاية: يحدد php.ini سكربت PHP الذي عنده تبدأ العملية ، يتم تحميل الملفات في الذاكرة (التحميل المسبق). بالاقتران مع OPCache ووظيفة التحميل التلقائي
، يمكن أيضًا تجميع ملفات الملحن وربطها مرة واحدة ، وبعد ذلك ستكون متاحة لجميع الطلبات اللاحقة. بفضل هذا ، لا يحتاج PHP إلى تنزيل الملفات وتجميعها مع كل طلب.
ومع ذلك ، لم يتفق مطورو الملحن على الطريقة التي يجب أن يساعد بها التحميل المسبق ، بالإضافة إلى توفير وظائف بدء التشغيل. الحقائق هي كما يلي:
- تم الإعلان عن التحميل المسبق لأول مرة في PHP 7.4 ؛
- لا يوجد أي تعليمات من الملحن للمساعدة في تحميل الملفات مسبقًا ؛
- للتحميل المسبق ، تحتاج إلى الوصول إلى php.ini ، أي إلى العملية نفسها ؛
- التحميل المسبق لجميع الملفات لن يؤدي بالضرورة إلى تحسين الأداء مقارنة بتحميل الملفات الأكثر طلبًا فقط.
بمعنى آخر ، يمكن فقط لأولئك الذين لديهم حق الوصول الكامل إلى الخوادم استخدام التحميل المسبق. يستثني ذلك الخوادم المشتركة وبعض حلول PaaS التي لا تتضمن العمل مع php.ini.
لذلك ، كيف يمكن أن يساعد الملحن في التحميل المسبق نظرًا لأن هذا الابتكار؟ هذا هو رأيي.
كيف التحميل المسبق يجب أن تعمل
يجب أن تستند آلية التحميل المسبق إلى قائمة الملفات التي سيتم
تحميلها وتخزينها في الذاكرة عند بدء التشغيل. ونظرًا لأن هذه قائمة ، نحتاج إلى العمل مع مجموعة من الملفات والسماح لـ Composer بالقيام بكل العمل ، بدلاً من
تحميل كل ملف يدويًا.
يجب أن يأخذ الملحن قائمة الملفات المحددة بواسطة التطبيق (مشروع الجذر) ويجمع كل شيء في ملفات يمكن لـ PHP استخدامها دون أي صعوبة.
في الوقت نفسه ، نحتاج إلى القدرة على إضافة وإزالة الحزم من آلية التحميل المسبق.
يجب ألا يعمل التحميل المسبق مطلقًا على مستوى الحزمة ، حيث تقع على عاتق المطور مسؤولية تمكين التحميل المسبق لكل حزمة أو تعطيله.
يجب أن يكون التحميل المسبق في الملحن اختياريًا. يجب أن يكون المطور قادرًا على تعطيله حتى يستخدم PHP أداة التحميل المسبق الخاصة به ، والتي يمكن أن تعمل على أساس تحليل OPCache - يعتمد ذلك على تحميل التطبيق ويعمل بكفاءة أكبر بكثير من مجرد التحميل المسبق لجميع الملفات.
كل شيء يبدأ في preload.json
من أجل عدم تعقيد النظام ، ضع الملف preload.json في جذر المشروع. سيقوم بسرد ملفات التحميل المسبق التي يستطيع الملحن تحديدها. نظرًا لأن هذا ملف JSON ، فيمكن للمطور إنشاءه بمساعدة أمر خاص. أعتقد أنه سيكون من الرائع أن يكون لدى Composer أداة لإنشاء ملف JSON القائم على البرنامج النصي.
{ "pre-compile": [ "my-script.php", "my-other-script.php" ], "extensions": [ "php" ], "files": [ "app/*", "config/", "helpers.php", "app/Models/*", "app/Controllers/*/Http/*", "app/Views/Compiled*.php" ], "namespace": [ "App\\Models", "App\\Controllers\\", "App\\Views\\MainView", "Vendor\\Package\\*", ], "packages": { "symfony/http-client": true, "robert/*-client": true, "vendor/package": { "files": true, "namespace": true }, "foo/bar": { "files": [ "helpers.php", "loaders/*" ], "namespace": [ "Foo\\Bar\\DynamicLoaders\\*", "Foo\\Bar\\Clients" ] } }, "output": "preload-compiled.php" }
يتيح لك استخدام preload.json التحقق بسرعة من تضمين التحميل المسبق في المشروع: إذا كان الملف مفقودًا ، فإن التحميل المسبق غير مدعوم أو غير مرغوب فيه.
دعونا نرى ما تفعله المفاتيح.
ما قبل الترجمةسيتم تنفيذ هذه الملفات بواسطة الملحن. يجب أن يعرض كل برنامج نصي مجموعة من مسارات الملفات المطلقة لإضافتها إلى قائمة التحميل المسبق ، والتي ستلعب دور القائمة الرئيسية.
"pre-compile": [ "my-script.php", "my-other-script.php" ]
سيتم تنفيذ هذه الملفات بالترتيب المحدد.
الهدف هو أن ينشئ المطور قائمة بالملفات كما يراه مناسبًا ، بدلاً من الاعتماد على ملف JSON واحد. سيتم تنفيذ هذه الملفات أولاً. ونعم ، يمكنك فقط تطبيق preload.json باستخدام هذا المفتاح. بما أننا نتحدث عن ملفات PHP ، عند تجميع صفيف ، يمكنك إضافة ملفات أخرى.
ملحقاتهذه قائمة ملحقات الملفات التي تحتاج إلى تحميلها مسبقًا. بشكل افتراضي ، يتم أخذ الملفات ذات امتداد php فقط.
"extensions": ["php", "php5", "php7"]
على سبيل المثال ، يمكنك إضافة دليل مليء بملفات * .phtml ، بما في ذلك بعض ملفات PHP المفيدة ، وسيقوم الملحن بتحديدها فقط ، وليس كامل محتويات الدليل.
كما فهمت ، يمكن استبدال هذه العملية بإضافة الملفات يدويًا.
ملفاتيطلب هذا المفتاح من الملحن تنزيل جميع الملفات من القائمة التي ترتبط مساراتها بموقع composer.json.
"files": [ "helpers.php", "app/Models/*", "app/Controllers/*/Http/*", "app/Views/Compiled*.php", ]
معرفة القائمة سهلة:
- استخدام المسارات النسبية لإضافة الملفات والدلائل ؛
- من الدلائل ، ستتم إضافة الملفات الفرعية المخزنة فيها فقط (وليس بشكل متكرر) ؛
- يشار إلى المسارات العودية بنهاية النجمة (*) ؛
- باستخدام هذا الرمز ، يمكنك أيضًا ، على سبيل المثال ، إضافة ملفات وأدلة معينة:
src/Clients/*/Stores
أو src/Model*.php
.
تعد إضافة الملفات عن طريق القناع دون تحديد أو إنشاء برامج نصية خاصة بالتطبيقات مفيدة بشكل خاص عند تطوير التطبيقات الكبيرة.
إذا كنت بحاجة فقط إلى تحميل جميع الملفات مسبقًا باستخدام
مفتاح التحميل
التلقائي في ملف Composer JSON ، فاضبطه على "
true
.
مساحة الاسميخبر هذا المفتاح الملحن بتحميل الملفات بمساحة اسم أو فئة معينة مثل
file
أو
directory
. تسمح لك نفس الآلية بشكل ديناميكي باستدعاء أسماء المساحات من الحزم المثبتة الأخرى.
"namespaces": [ "App\\Models", "App\\Controllers\\", "App\\Views\\MainView", "Vendor\\Package\\*", ]
هذا مناسب أيضًا عند العمل على التطبيقات الكبيرة التي تعتمد بشكل أكبر على مساحات الأسماء ، بدلاً من الملفات التي يمكن أن تتغير في أي وقت. سيقوم الملحن باستخراج الملفات تلقائيًا وفقًا لمساحة الاسم ووضعها في قائمة.
حزميتيح لك هذا المفتاح تحميل الملفات الأخرى المسجلة من الحزم الخارجية ، مثل الملفات المساعدة أو الفئات المرتبطة بمساحة الاسم.
"packages": { "symfony/http-client": true, "robert/*-client": true, "vendor/package": { "files": true, "namespace": true }, "foo/bar": { "files": { "helpers.php", "loaders/*" }, "namespace": [ "Foo\\Bar\\DynamicLoaders\\*", "Foo\\Bar\\Clients" ] } }
كل شيء بسيط للغاية هنا: إذا كانت القيمة صحيحة ، فسيتم تحميل جميع محتويات
مفتاح التحميل
التلقائي في ملف composer.json لهذه الحزمة. خلاف ذلك ، يمكنك التحكم بشكل أكثر دقة في إضافة التحميل المسبق.
إذا كانت قيمة المفتاح صحيحة ، فسيتم تنزيل جميع الملفات المسجلة في التحميل
autoload
. القيمة الافتراضية
false
. هذا صحيح أيضًا لمفتاح
namespace
.
يمكنك أيضًا تحديد الملفات الفردية أو مساحات الأسماء باستخدام هذه القاعدة. ولكن في هذه الحالة ، لن يتم استخدام مفتاح
autoload
.
إنتاجهذا هو ببساطة اسم ملف قائمة التحميل المسبق المترجمة.
"output": "preload-compiled.php"
سهل التجميع
قائمة التحميل المسبق لدينا جاهزة ، ويمكننا استدعاء الملحن لتجميع البرنامج النصي للتحميل الرئيسي.
composer preload
نتيجة لذلك ، سيتم إنشاء preload-compiled.php مع جميع الملفات التي يجب على PHP تحميلها مسبقًا. بالطبع ، يمكنك تغيير اسم الملف كما يحلو لك.
تحتاج أيضًا إلى تجاوز مفاتيح
preload
المعلمات.
composer preload \ --input=my-custom-preload-list.json \ --output=my-preload.php
تعطيل افتراضيا
المشاريع بدون preload.json ستُرجع خطأً إذا حاولت ترجمة ملف للتحميل المسبق. والسبب هو أن الملحن لن (ولا ينبغي) تخمين ما يجب تحميله مسبقًا.
اسمحوا لي أن أذكرك بأن التحميل المسبق لا يتعارض مع الوظائف العادية للملحن. نظرًا لأن هذا أمر وحدة تحكم ، مع التطوير المحلي ، يمكنك التخلي عن التحميل المسبق تمامًا. الشيء الوحيد الذي تحتاج إليه آلية التحميل المسبق للملحن هو ملف التحميل التلقائي ، والذي يجب إنشاؤه في حالة فقده. حسنا ، بعد كل شيء ، ما يقرب من عام 2020 هو في الفناء ، يتم استخدام PSR-4 في كل مكان ، أليس كذلك؟
يؤدي
يجب أن تحصل على ملف php بشيء مثل هذا:
<?php
في الواقع ، هذه مجرد قائمة بالملفات التي سيتم تحميلها مسبقًا باستخدام وظيفة التحميل التلقائي في الملحن. سيقوم PHP بتنفيذ هذا الملف مرة واحدة ، وسيصبح السجل.
آمل مخلصًا أن يكون لدى Composer طريقة لتحميل الملفات دون الحاجة إلى كتابة الاختراق.
نظرًا لأن الطريقة الموضحة أعلاه ليست جزءًا من kernel Composer ، فلا يزال بإمكانك تحديد الملفات الأكثر أهمية للتحميل المسبق على أساس تحليل OPCache دون لمس الملفات الأقل حاجة. تخيل أنه بدلاً من تحميل 1500 ملف مسبقًا بسعة 100 ميجابايت ، يمكنك تنزيل 150 ملفًا فقط بسعة 10 ميجابايت ، مع الحفاظ على 99٪ من الأداء الأصلي.
نحن نقوم مسبقاً بتحميل مشروع PHP 7.4 في سطر واحد
بعد فترة وجيزة من
كتابتي مقالة حول كيف يمكن أن يساعدك الملحن في التحميل المسبق للمشروع ،
قتل Seldaek (عضو في فريق تطوير الملحن)
كل الأمل في أن يكون لدى Composer خيار التحميل المسبق للمشروع بسهولة إلى عملية PHP من مدير الحزم.
(...) سأوضح: أنا متأكد من أننا في المستقبل القريب لن نضيف أي شيء متعلق بالتحميل المسبق إلى الملحن.
لماذا؟ يعد التحميل المسبق لـ PHP أكثر من مشكلة تطوير (بدلاً من مشكلة تبعية) ؛ حيث يتم حلها عن طريق تحرير php.ini يدويًا - يمكن للمطورين فقط القيام بذلك إذا تمكنوا من إدارة PHP بأنفسهم.
لكن هذا لا يمنعني من إنشاء حزمة خاصة لي لتحميل المشروع مسبقًا. وانت ايضا
التحميل المسبق والمقاييس
التحميل المسبق يمكن أن يكون أداة جيدة لزيادة
بسيطة ورخيصة في الإنتاجية دون معالجة جادة.
ولكن المشكلة ليست في
كيفية التحميل المسبق ، ولكن
ماذا . إن تحميل الأطر بأكملها والآلاف من الملفات سوف تستنزف الذاكرة بسرعة ، وبالتالي فإن القيام بذلك بشكل عمياء ليس خيارًا ، على الأقل في المشروعات الكبيرة. يُنصح بتنزيل الملفات الأكثر طلبًا فقط. ولكن كيف تحددهم؟
لحسن الحظ ، يسمح
OPCache opcache_get_status () بجمع البيانات حول أي الملفات يتم الوصول إليها على الأكثر. لا يمكنك فقط معرفة الملفات الأكثر طلبًا ، ولكن حتى مقدار الذاكرة التي تستهلكها بعض الوقت بعد بدء تشغيل التطبيق.
يوصى بالانتظار إما لمدة أسبوع أو حتى لحظة تسجيل OPCache لعدد معين من الزيارات. كل هذا يتوقف على التطبيق ، لكنك تحصل على هذه النقطة.
لذلك دعونا ننشئ قائمة التحميل المسبق على أساس إحصاءات من الملفات الأكثر شعبية. أنا قدمت حزمة لهذا الغرض.
تخيل ... Preloader!
ستنشئ هذه الحزمة تلقائيًا قائمة التحميل المسبق للتطبيق الخاص بك. سيجمع إحصائيات استخدام OPCache ، ويقوم بترتيب الملفات حسب عدد الزيارات وإنشاء قائمة بحيث لا يتجاوز إجمالي حجم الملف العتبة المحددة.

أنا في حيرة لفترة طويلة في البحث عن أفضل استراتيجية لإنشاء قائمة. وتوصلت إلى استنتاج مفاده أنه من الأفضل إضافة جميع الملفات إليه حتى تعمل في حدود الذاكرة ، والتي تصل إلى 32 ميغابايت بشكل افتراضي للحزم. سيتم فرز الملفات حسب عدد الزيارات ، وسيتم استبعاد الحزمة نفسها تلقائيًا.
بمعنى آخر ، سيقوم PHP بتحسين أداء التطبيق عند معالجة معظم الطلبات إليه.
وكيفية استخدامها؟ أخبر الملحن Autoloader حيث يكتب البرنامج النصي Preloader ، والانتهاء من ذلك.
use DarkGhostHunter\Preloader\Preloader; Preloader::make() ->autoload('vendor/autoload.php') ->output('preload.php') ->generate();
بالطبع ، يجب عليك اختيار وقت الإنشاء ، لكن هذه هي النقطة الأساسية. يمكنك القيام بذلك بشكل عشوائي وإعادة كتابة القائمة ، على سبيل المثال ، لكل طلب 100.
use DarkGhostHunter\Preloader\Preloader; Preloader::make() ->whenOneIn(100) ->autoload('vendor/autoload.php') ->output('preload.php') ->overwrite() ->generate();
ستحصل على برنامج نصي للتحميل المسبق الجاهزة يمكنك وضعه في php.ini.
<?php require_once '/www/app/vendor/autoload.php'; $files = [ '/www/app/ClassFoo.php', '/www/app/ClassBar.php', '/www/app/ClassBaz.php', '/www/app/ClassQuz.php', '/www/app/ClassQux.php', '/www/app/vendor/author/package/src/Example.php',
وهذا كل شيء. جربه بنفسك:
darkghosthunter / preloader - Packagist .