Kami di Badoo aktif beralih ke PHP 7.4 dan sangat antusias tentang peluang untuk menggunakan fungsi preload baru. Belum lama ini kami
membicarakan eksperimen kami dengannya.
Tampaknya, komunitas sama bersemangatnya dengan kami. Pengembang framework secara aktif
mendiskusikan kemungkinan memperkenalkan preload (dan beberapa telah
membuat dukungannya ). Sekarang giliran manajer ketergantungan Composer.
Italo Baeza menulis
sebuah artikel di mana dia menyatakan pendapatnya tentang bagaimana Composer harus bekerja dengan preload. Saya memutuskan untuk membagikan terjemahan dari teks ini, dan pada saat yang sama terjemahan dari
artikelnya yang lain , tentang bagaimana para pengembang Komposer sendiri menjawab proposal tersebut, serta tentang alat baru yang membuat bekerja dengan preload lebih mudah.
Bagaimana Komposer Harus Dimuat di PHP 7.4
Preload adalah salah satu fitur penting yang ditawarkan PHP 7.4 kepada pengembang yang membutuhkan kinerja yang lebih baik. Fungsi ini dapat disebut "pemanasan" sebelum menerapkan mesin JIT, yang akan muncul (atau akan muncul) di PHP 8. Sebelum itu, preloading akan cukup, dan siapa tahu, mungkin mereka dapat bekerja bersama-sama.
Apa fungsi preload dijelaskan dalam
artikel ini . Intinya sangat sederhana: php.ini menentukan skrip PHP yang ketika proses dimulai, file dimuat ke dalam memori (preload). Dalam kombinasi dengan OPCache dan fungsi autoloader
, file Composer juga dapat dikompilasi dan ditautkan satu kali, setelah itu mereka akan tersedia untuk semua permintaan berikutnya. Berkat ini, PHP tidak perlu mengunduh dan mengkompilasi file dengan setiap permintaan.
Namun, pengembang Komposer tidak setuju tentang bagaimana seharusnya membantu preload, selain menyediakan fungsi startup. Faktanya adalah sebagai berikut:
- preloading pertama kali diumumkan dalam PHP 7.4;
- tidak ada arahan Komposer untuk membantu memuat file;
- untuk melakukan preload, Anda memerlukan akses ke php.ini, yaitu ke proses itu sendiri;
- preloading semua file tidak serta merta meningkatkan kinerja dibandingkan dengan preloading hanya file yang paling banyak diminta.
Dengan kata lain, hanya mereka yang memiliki akses penuh ke server yang dapat menggunakan preloading. Ini tidak termasuk server bersama dan beberapa solusi PaaS yang tidak melibatkan bekerja dengan php.ini.
Jadi, bagaimana Composer dapat membantu memuat sebelumnya mengingat ini adalah sebuah inovasi? Ini pendapat saya.
Bagaimana preload seharusnya bekerja
Mekanisme untuk preloading harus didasarkan pada daftar file yang akan
dimuat dan disimpan dalam memori saat startup. Dan karena ini adalah daftar, kita perlu bekerja dengan berbagai file dan membiarkan Komposer melakukan semua pekerjaan, daripada
memuat setiap file secara manual.
Composer harus mengambil daftar file yang ditentukan oleh aplikasi (proyek root) dan mengkompilasi semuanya menjadi file yang dapat digunakan PHP tanpa kesulitan.
Pada saat yang sama, kita membutuhkan kemampuan untuk menambah dan menghapus paket dari mekanisme preload.
Preloading tidak boleh bekerja di tingkat paket, karena itu adalah tanggung jawab pengembang untuk mengaktifkan atau menonaktifkan preloading setiap paket.
Preloading dalam Komposer harus opsional. Pengembang harus dapat menonaktifkannya sehingga PHP menggunakan preloadernya sendiri, yang dapat bekerja berdasarkan analisis OPCache - tergantung pada beban aplikasi dan bekerja jauh lebih efisien daripada hanya preloading semua file.
Semuanya dimulai di preload.json
Agar tidak menyulitkan sistem, letakkan file preload.json di root proyek. Ini akan mencantumkan file preload yang dapat dipilih oleh Composer. Karena ini adalah file JSON, pengembang bahkan dapat membuatnya dengan bantuan perintah khusus. Saya pikir akan bagus jika Komposer memiliki utilitas untuk membuat file JSON berbasis script.
{ "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" }
Menggunakan preload.json memungkinkan Anda untuk dengan cepat memeriksa apakah preloading termasuk dalam proyek: jika file tersebut hilang, maka preloading tidak didukung atau tidak diinginkan.
Mari kita lihat apa yang dilakukan kunci.
pra-kompilasiFile-file ini akan dieksekusi oleh Komposer. Setiap skrip harus mengembalikan array jalur file absolut untuk menambahkannya ke daftar preload, yang akan memainkan peran daftar utama.
"pre-compile": [ "my-script.php", "my-other-script.php" ]
File-file ini akan dieksekusi dalam urutan yang ditentukan.
Tujuannya adalah agar pengembang membuat daftar file yang menurutnya sesuai, daripada mengandalkan file JSON tunggal. File-file ini akan dieksekusi terlebih dahulu. Dan ya, Anda hanya dapat mengimplementasikan preload.json dengan kunci ini. Karena kita berbicara tentang file PHP, ketika menyusun array, Anda bahkan dapat menambahkan file lain.
ekstensiIni adalah daftar ekstensi file yang harus dimuat sebelumnya. Secara default, hanya file dengan ekstensi php yang diambil.
"extensions": ["php", "php5", "php7"]
Misalnya, Anda dapat menambahkan direktori yang diisi dengan file * .phtml, termasuk beberapa file PHP yang berguna, dan Composer hanya akan memilihnya, dan bukan seluruh isi direktori.
Seperti yang Anda pahami, proses ini dapat diganti dengan menambahkan file secara manual.
fileKunci ini memberitahu Composer untuk mengunduh semua file dari daftar yang jalurnya relatif terhadap lokasi composer.json.
"files": [ "helpers.php", "app/Models/*", "app/Controllers/*/Http/*", "app/Views/Compiled*.php", ]
Mengetahui daftar itu mudah:
- gunakan jalur relatif untuk menambahkan file dan direktori;
- dari direktori hanya file anak yang disimpan di dalamnya yang akan ditambahkan (tidak secara rekursif);
- jalur rekursif ditandai dengan tanda bintang (*);
- menggunakan simbol ini Anda juga dapat, misalnya, menambahkan file dan direktori tertentu:
src/Clients/*/Stores
atau src/Model*.php
.
Menambahkan file dengan mask tanpa memilih secara manual atau membuat skrip khusus aplikasi sangat berguna saat mengembangkan aplikasi besar.
Jika Anda hanya perlu memuat semua file menggunakan
kunci autoload di file JSON Composer, atur menjadi
true
.
namespaceKunci ini memberitahu Composer untuk memuat file dengan namespace atau nama kelas yang diberikan seperti
file
atau
directory
. Mekanisme yang sama memungkinkan Anda untuk memanggil nama ruang secara dinamis dari paket yang diinstal lainnya.
"namespaces": [ "App\\Models", "App\\Controllers\\", "App\\Views\\MainView", "Vendor\\Package\\*", ]
Ini juga nyaman ketika bekerja pada aplikasi besar yang lebih bergantung pada ruang nama, daripada pada file yang dapat berubah kapan saja. Composer akan secara otomatis mengekstrak file sesuai dengan namespace dan memasukkannya ke dalam daftar.
paketKunci ini memungkinkan Anda untuk memuat file lain yang terdaftar dari paket eksternal, seperti file tambahan atau kelas yang terkait dengan namespace.
"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" ] } }
Semuanya sangat sederhana di sini: jika nilainya benar, maka seluruh isi
kunci autoload dalam file composer.json dari paket ini akan dimuat. Jika tidak, Anda dapat lebih mengontrol penambahan preload.
Jika nilai kunci benar, maka itu akan mengunduh semua file yang terdaftar dalam
autoload
. Nilai standarnya
false
. Ini juga berlaku untuk kunci
namespace
.
Anda juga dapat memilih file individu atau ruang nama dengan aturan ini. Tetapi dalam kasus ini, kunci
autoload
tidak akan digunakan.
keluaranIni hanyalah nama file daftar preload yang dikompilasi.
"output": "preload-compiled.php"
Perakitan mudah
Daftar pra-muat kami siap, dan kami dapat memanggil Komposer untuk mengkompilasi skrip pra-muat utama.
composer preload
Akibatnya, preload-compiled.php akan dibuat dengan semua file yang harus dimuat oleh PHP. Tentu saja, Anda dapat mengubah nama file sesuai keinginan.
Anda juga perlu mengganti kunci
preload
parameter.
composer preload \ --input=my-custom-preload-list.json \ --output=my-preload.php
Dinonaktifkan secara default
Proyek tanpa preload.json akan mengembalikan kesalahan jika Anda mencoba mengkompilasi file untuk preloading. Alasannya adalah bahwa Komposer tidak akan (dan tidak seharusnya) menebak apa yang harus dimuat.
Biarkan saya mengingatkan Anda bahwa preload tidak mengganggu fungsi Composer yang normal. Karena ini adalah perintah konsol, dengan pengembangan lokal, Anda dapat sepenuhnya mengabaikan preloading. Satu-satunya hal yang dibutuhkan mekanisme preload Composer adalah file Autoload, yang harus dihasilkan jika hilang. Yah, setelah semua, hampir tahun 2020 di halaman, PSR-4 digunakan di mana-mana, kan?
Hasil
Anda harus mendapatkan file php dengan sesuatu seperti ini:
<?php
Bahkan, ini hanya daftar file yang akan dimuat menggunakan fungsi autoloader di Composer. PHP akan mengeksekusi file ini sekali, dan itu akan menjadi sejarah.
Saya sangat berharap bahwa Komposer akan memiliki beberapa cara untuk memuat file tanpa harus menulis peretasan.
Karena metode yang dijelaskan di atas bukan bagian dari kernel Komposer, Anda masih dapat memilih file yang paling penting untuk preloading berdasarkan analisis OPCache tanpa menyentuh yang kurang dibutuhkan. Bayangkan bahwa alih-alih melakukan prapembuatan 1.500 file dengan kapasitas 100 MB, Anda dapat mengunduh hanya 150 file dengan kapasitas 10 MB, sambil mempertahankan 99% dari kinerja aslinya.
Kami memuat proyek PHP 7.4 dalam satu baris
Segera setelah saya menulis artikel tentang bagaimana Komposer dapat membantu Anda melakukan preload proyek,
Seldaek (anggota tim pengembangan Komposer)
membunuh semua harapan bahwa Komposer akan memiliki pilihan yang mudah untuk memuatkan proyek ke dalam proses PHP dari manajer paket.
(...) Saya akan menjelaskan: Saya yakin bahwa dalam waktu dekat kami tidak akan menambahkan apa pun yang terkait dengan prapembuatan ke Komposer.
Mengapa Preloading dalam PHP lebih merupakan masalah pengembangan (bukan ketergantungan), diselesaikan dengan mengedit secara manual php.ini - hanya pengembang yang dapat melakukannya jika mereka sendiri yang mengelola PHP.
Tetapi ini tidak menghentikan saya untuk membuat paket sendiri untuk melakukan preload proyek. Dan kamu juga.
Preload dan Metrik
Preloading dapat menjadi alat yang baik untuk peningkatan produktivitas yang
sederhana dan murah tanpa pemrosesan serius.
Tapi masalahnya bukan
bagaimana melakukan preload, tapi
apa . Preloading seluruh kerangka kerja dan ribuan file akan dengan cepat menghabiskan memori, sehingga melakukannya secara membabi buta bukanlah suatu pilihan, setidaknya dalam proyek-proyek besar. Dianjurkan untuk hanya mengunduh file yang paling banyak diminta. Tetapi bagaimana cara mendefinisikannya?
Untungnya, OPCache memungkinkan
opcache_get_status () untuk mengumpulkan data tentang file mana yang paling banyak diakses. Anda tidak hanya dapat mengetahui file mana yang paling diminati, tetapi bahkan berapa banyak memori yang mereka konsumsi beberapa saat setelah aplikasi dimulai.
Dianjurkan untuk menunggu seminggu atau sampai saat OPCache mendaftarkan sejumlah hit. Itu semua tergantung pada aplikasi, tetapi Anda mendapatkan intinya.
Jadi mari kita buat daftar preload berdasarkan statistik dari file paling populer. Saya membuat paket untuk ini.
Bayangkan ... Preloader!
Paket ini secara otomatis akan membuat daftar preload untuk aplikasi Anda. Ini akan mengumpulkan statistik penggunaan OPCache, mengurutkan file dengan jumlah klik dan membuat daftar sehingga ukuran file total tidak melebihi ambang yang ditentukan.

Saya bingung untuk waktu yang lama dalam mencari strategi terbaik untuk membuat daftar. Dan saya sampai pada kesimpulan bahwa yang terbaik adalah menambahkan semua file ke dalamnya sampai Anda mengalami batas memori, yang untuk paket adalah 32 MB secara default. File akan diurutkan berdasarkan jumlah klik, dan paket itu sendiri akan secara otomatis dikecualikan.
Dengan kata lain, PHP akan meningkatkan kinerja aplikasi saat memproses sebagian besar permintaan.
Dan bagaimana cara menggunakannya? Beri tahu Pembuat Komposer tempat menulis skrip Prapuat, dan Anda selesai.
use DarkGhostHunter\Preloader\Preloader; Preloader::make() ->autoload('vendor/autoload.php') ->output('preload.php') ->generate();
Tentu saja, Anda harus memilih kapan untuk menghasilkan, tetapi itulah intinya. Anda bahkan dapat melakukan ini secara acak dan menulis ulang daftar, misalnya, untuk setiap permintaan ke-100.
use DarkGhostHunter\Preloader\Preloader; Preloader::make() ->whenOneIn(100) ->autoload('vendor/autoload.php') ->output('preload.php') ->overwrite() ->generate();
Anda akan mendapatkan skrip preload yang sudah jadi yang bisa Anda masukkan ke dalam 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',
Dan itu dia. Cobalah sendiri:
darkghosthunter / preloader - Packagist .