Artikel ini bukan tentang fitur baru atau uji komparatif;
Hari ini, kami akan menyusun rencana pembaruan dan membahas potensi kesulitan utama berdasarkan contoh memperbarui proyek besar dari PHP 7. 4 sampai 8. 0. Sebagian besar langkah juga akan membantu saat merencanakan pemutakhiran dari versi sebelumnya
Kenapa sekarang?
PHP 8 dirilis empat bulan lalu. Pada saat penulisan, ada tiga versi tambalan PHP 8 yang memperbaiki bug kritis. Selain itu, paket pustaka dan komposer paling populer akhirnya menambahkan dukungan PHP 8. Meskipun untuk banyak perpustakaan, dukungan PHP 8 melibatkan perubahan versi di komposer, kompatibilitas yang dikonfirmasi secara resmi dari semua dependensi folder vendor adalah pemblokir untuk pemutakhiran
PrasyaratArtikel ini adalah retrospektif dari proses pembaruan PHP dari 7. 4 sampai 8. 0 di Oro Inc. repositori monolitik dengan 11 aplikasi web dan 45 modul proyek yang cukup besar berdasarkan Symfony 4. 4 LTS, 3M + LoC, dan lebih dari 600.000 kelas PHP, termasuk pengujian tetapi tidak termasuk vendor
Angka-angka tersebut tidak mencerminkan kerumitan proyek tetapi menunjukkan jumlah kode PHP yang telah diperbarui. Saya juga harus mencatat bahwa sebagian besar kode tidak menggunakan strict_types=1, yang secara teknis mempersulit pembaruan
Perubahan BesarSelain fitur-fitur baru, yang dalam banyak kasus memiliki alternatif, rilis utama memungkinkan pengembang bahasa PHP untuk merusak kompatibilitas ke belakang. Ini tidak terlalu buruk karena tidak perlu menulis ulang sebagian besar proyek untuk meningkatkan
Kompatibilitas rusak hanya dengan menghapus fitur yang ditandai sebagai usang dalam versi minor PHP 7 sebelumnya. 0–7. 4. Untuk memperkenalkan peningkatan, pengembang inti PHP juga dapat mengubah perilaku fungsi yang belum didokumentasikan sebelumnya atau telah diposisikan sebagai sesuatu yang tidak pasti sejak awal.
Sebagian besar perubahan terjadi di bidang perbandingan yang ketat dan jenis argumen yang ketat. Meskipun strict_types=1 tidak menjadi perilaku default, di versi 8, sebagian besar fungsi bawaan PHP telah menerima pengetikan argumen yang ketat, terkadang tanpa pengetikan
Memutakhirkan Ekstensi PHP
Jika Anda menggunakan ekstensi PHP pihak ketiga, perbarui terlebih dahulu. Meskipun untuk sebagian besar proyek ini seharusnya bukan masalah besar, ini dapat memblokir peningkatan lebih lanjut
Menentukan Paket Komposer Yang Perlu DitingkatkanPeringatan spoiler. pembaruan dependensi telah menjadi tahap pemutakhiran yang paling rumit
PHP memiliki banyak solusi siap pakai, sehingga sulit menemukan aplikasi tanpa ketergantungan pihak ketiga. Dalam kebanyakan kasus, komposer digunakan untuk mengelolanya. Alat ini memungkinkan Anda untuk menentukan ketergantungan pada paket dan menentukan apa yang disebut ketergantungan platform dari setiap paket, yang menyertakan versi PHP dan daftar ekstensi PHP yang diperlukan
Hal pertama yang terlintas dalam pikiran adalah menentukan versi PHP baru di root composer. json tetapi jangan terburu-buru dulu karena ini akan memicu rantai koreksi kesalahan yang tidak menyenangkan saat Anda menjalankan pembaruan komposer. Sebaiknya tanyakan langsung kepada komposer jika ada perpustakaan yang dapat mengganggu pemutakhiran. Untuk melakukannya, buka root proyek dan jalankan perintah berikut
composer why-not php 8Jika Anda menggunakan paket populer dan memperbarui dependensi ke versi terbaru tepat waktu, Anda akan melihat pesan ini dalam satu menit atau lebih
Sebagian besar akan melihat daftar dependensi "lengkap" yang perlu diperbarui untuk mendukung PHP 8. Lengkap dalam koma terbalik di sini karena selalu ada beberapa perpustakaan yang menetapkan batasan platform yang sangat lemah sejak awal atau tidak menentukannya sama sekali, yang berarti mereka sebenarnya tidak kompatibel dengan PHP 8. Jika proyek memiliki cakupan pengujian yang baik, proyek tersebut akan memainkan peran penting di masa depan dan membantu mengidentifikasi paket tersebut. Jika belum, mari kita coba dan optimis
Selanjutnya, dengan daftar lengkap dependensi yang tidak mendukung PHP 8 di versi saat ini, navigasikan ke ahli paket. org dan periksa apakah ada versi paket yang mendukung versi baru dari bahasa pemrograman. Aplikasi dengan OroCommerce dan OroCRM memiliki sekitar 300 paket komposer dalam dependensi, dan sejauh ini semuanya telah menerima pembaruan yang kompatibel. Dalam beberapa kasus, seperti dengan friendsofsymfony/rest-bundle, Anda bahkan tidak perlu memperbarui paket ke versi terbaru yang mengandung banyak ketidakcocokan mundur
Kontribusi untuk Open-SourceJika Anda menemukan beberapa paket yang tertinggal, tidak perlu khawatir. Komunitas PHP cukup aktif. Dalam kebanyakan kasus, meningkatkan ke PHP 8 tidak memerlukan investasi yang signifikan. Pertama, periksa cabang master untuk melihat apakah dukungan telah ditambahkan dan akan disertakan dalam rilis berikutnya. Kemudian, periksa daftar masalah dan tarik permintaan untuk menyebutkan PHP 8. Dalam kebanyakan kasus, alasan keterlambatan pembaruan dan penyelesaian masalah sudah teridentifikasi pada tahap ini
Namun, jika perpustakaan tidak digunakan secara luas dan metode sebelumnya tidak membuahkan hasil, Anda selalu dapat berkontribusi pada sumber terbuka. Dalam kasus kami, itu cukup untuk memperbaiki tes di symfony/acl-bundle dan menulis komentar untuk masalah di nelmio/security-bundle. Ini memungkinkan kami untuk mengurangi daftar dengan dua poin. Menjadi sangat aktif, para pengembang perpustakaan ini berhasil merilis versi baru hanya dalam beberapa jam setelah kontribusi minimal. Ini tidak selalu terjadi begitu cepat. Dalam beberapa kasus, kami harus menunggu beberapa minggu untuk rilis baru. Untuk sebagian besar proyek, ini bukan masalah besar. Jika perpustakaan tidak lagi didukung, masuk akal untuk memikirkan garpu atau alternatif;
Upgrade Paket KomposerMemperbarui paket komposer mungkin merupakan tahap terpanjang untuk sebagian besar proyek karena, bersama dengan dukungan versi PHP yang baru, pengembang ekstensi aktif sering kali merilis versi utama dan merusak kompatibilitas ke belakang. Namun kabar baiknya adalah sebagian besar perubahan dijelaskan secara mendetail di catatan rilis atau changelog di root repositori. Kompilasi daftar perubahan, dan itu adalah sebagian besar cakupan peningkatan Anda
Tingkatkan Estimasi Waktu
Bergantung pada bagaimana dependensi digunakan (misalnya, apakah hanya antarmuka yang digunakan atau ada banyak penggantian), upaya pemutakhiran dari satu paket mungkin berbeda. Itu sering dapat diidentifikasi dengan membaca daftar perubahan dan melakukan pencarian cepat pada kode berdasarkan ruang nama, kelas, dan nama fungsi yang telah berubah. Ini memungkinkan untuk mendapatkan perkiraan perkiraan waktu pembaruan dengan segera
Memperbarui Dependensi
Penting untuk dicatat bahwa sebagian besar, versi dependensi baru dengan dukungan untuk PHP 8 masih mendukung PHP 7. 4, sehingga pembaruan dapat dilakukan secara bertahap, paket demi paket
Jika Anda telah berhasil menyelesaikan pembaruan komposer dan mencapai tahap ini, selamat. Folder vendor, yang biasanya berisi sebagian besar kode PHP dalam proyek, secara teoritis kompatibel. Kita dapat melangkah lebih jauh dan memperbarui kode secara langsung
Peretasan untuk Ketergantungan yang Tidak Kompatibel
Jika Anda perlu memperbarui sekarang untuk menguji kompatibilitas pustaka yang tidak kompatibel sebelum memperbaruinya ke PHP 8, berikut adalah beberapa trik untuk melakukannya
- Beri tahu komposer bahwa Anda menggunakan PHP 7. 4 tetapi jalankan kode di PHP 8
Karena hampir semua perpustakaan pihak ketiga bekerja secara bersamaan dengan PHP 8 dan 7. 4, Anda dapat memperoleh pembaruan dan, pada saat yang sama, berhasil menyelesaikan pembaruan komposer dengan persyaratan ketergantungan tingkat platform yang tidak kompatibel. Composer mengabaikan versi sebenarnya dari PHP jika konfigurasi platform tingkat proyek ditentukan
- Mendefinisikan ulang kelas yang tidak kompatibel. Jika DiC digunakan, biasanya cukup sederhana. Hiasi, atau bahkan ganti sepenuhnya, kelas asli melalui konfigurasi wadah. Bahkan jika kelas di vendor dinyatakan sebagai final, itu selalu dapat ditimpa pada tingkat di komposer. json, misalnya, suka. Tentu saja, ini berantakan, tetapi seperti yang dikatakan Marco Pivetta, peretasan akan terlihat seperti peretasan
Memperbarui Kode Anda
Belum waktunya untuk fitur baru karena Anda harus terlebih dahulu memperbaiki apa yang rusak. Di sini, tes otomatis akan berguna. Dengan bantuan mereka, Anda dapat menginstal proyek pada versi baru, menjalankan semua pengujian, dan memperkirakan jumlah pekerjaan lebih lanjut dalam hitungan beberapa jam. Misalnya, di Oro, sebagian besar fungsi dicakup oleh pengujian Behat, fungsional, dan unit. Sekadar memberi gambaran tentang jumlah tes, total waktu tes lebih dari 30 jam. Ini memungkinkan kami untuk melihat gambar yang lengkap dan akurat segera setelah memperbarui vendor dan memperbaiki masalah pemasangan aplikasi
Konfigurasi Sebelum Pengujian
Jika rekan-rekan developer sudah rajin dan sudah menggunakan pengetikan yang ketat, seharusnya update berjalan lancar; . Itulah mengapa penting untuk menguji proyek, secara otomatis atau manual, dan menyusun daftar apa yang rusak, menuliskan pengecualian dari log jika ada. Pengujian masuk akal dengan pesan kesalahan yang ketat diaktifkan di php. ini
error_reporting = E_ALLTentu saja, asalkan proyek sebelumnya bekerja dalam mode ini tanpa kesalahan. Jika tidak, dikombinasikan dengan display_errors=off, ini akan membantu Anda melihat log kesalahan dan peringatan tanpa merusak struktur halaman. Jika lognya tidak panjang, daftar ini akan terbukti sangat berguna
Deteksi Kesalahan Otomatis
Berkat AST oleh Nikita Popov, ada cukup banyak penganalisa statis di PHP yang dapat menunjukkan area masalah dan terkadang bahkan memperbarui kode secara otomatis
- Phpstan dan Psalm adalah alat paling populer untuk membantu mempertahankan pengetikan yang ketat. Tetapi jika mereka belum pernah digunakan dalam proyek sebelumnya, tidak perlu terburu-buru, karena mereka akan menemukan banyak masalah. Namun, tidak semuanya memerlukan perbaikan segera untuk meningkatkan ke PHP 8
- Rektor akan membantu untuk "menulis ulang" kode menggunakan perbaikan gula sintaksis, tetapi tidak akan menunjukkan masalah yang mendesak
- Dari podcast “Lima Menit PHP”, saya belajar tentang plugin PHPCompatibility yang cukup menarik untuk PHP_CodeSniffer, yang seharusnya menunjukkan masalahnya. Sayangnya, apa yang sebenarnya dilakukannya hanya menunjukkan beberapa kesalahan positif dalam proyek kami, jadi saya tidak dapat merekomendasikannya. Plugin tidak memeriksa kompatibilitas nyata; . Misalnya, ini menunjukkan bahwa kami tidak dapat menggunakan "string" di ruang nama yang dimulai dengan versi 7. 0, meskipun masih berfungsi tanpa kesalahan
PhpStorm ternyata yang paling berguna. Secara default, IntelliJ IDEA hanya memvalidasi file yang terbuka, tetapi memiliki fitur untuk menganalisis keseluruhan proyek. Untuk melakukannya, kode yang Anda tulis harus sempurna dari perspektif PhpStorm; . Di sini, kami dapat meluncurkan satu inspeksi khusus
Ketika Anda melihat kesalahan, salin namanya, pilih folder kode di file tree, pilih Code> Run inspection by name di menu PhpStorm, masukkan nama inspeksi. Sangat cepat, Anda akan mendapatkan hasil untuk keseluruhan proyek. Misalnya, saat memperbarui pustaka pihak ketiga, "Pemeriksaan Hierarki Kelas" akan menampilkan tanda tangan metode yang perlu diperbaiki dalam kode setelah memperbarui vendor
Perubahan yang perlu diingat
Jika tidak ada tes otomatis pada proyek atau cakupannya tidak lengkap, Anda perlu memperhatikan fungsi penyortiran dan pembanding
Penyortiran
Perilaku fungsi pengurutan (usort,…) telah berubah. Pertama, fungsi perbandingan yang digunakan dalam pengurutan sekarang harus mengembalikan -1, 0, atau 1
True and false still work but trigger a deprecation notice. The spaceship operator `` will be helpful here. But most importantly, sorting of the elements with the same weight now leaves the order of the elements unchanged, which is different from the behavior in PHP 7.4. Suppose the project is large enough and has a modular structure like at Oro. In that case, problems may arise in extensions that are implemented using a chain of responsibilities, decorators, or a simple registry with a sorted list of add-ons. In our case, some extensions that depended on the order of execution were broken, because the sorting priority was not clearly specified. For example, the order of columns and rows in some tables changed, and in other places, we received an exception.
usort($exportFiles, function (File $a, File $b) {- return $b->getMtime() > $a->getMtime();
+ return $b->getMtime() <=> $a->getMtime();
});
Peretasan untuk menyimpan penyortiran, seperti di PHP 7
$comparisonClosure = function (ExtensionVisitorInterface $a, ExtensionVisitorInterface $b) {if ($a->getPriority() === $b->getPriority()) {
- return 0;
+ return -1;
}
return $a->getPriority() > $b->getPriority() ? -1 : 1;
}_
Pada gambar di bawah, hanya dua Ekstensi terakhir yang memiliki prioritas eksplisit. Di sini, perhatikan item 4
Perbandingan Non-Ketat
Perbandingan non-ketat antara angka dan string non-numerik sekarang berfungsi dengan mentransmisikan angka ke string dan membandingkan string. Kami memiliki masalah dengan dua contoh pertama
╔═══════════════╦════════╦═══════╗║ Comparison ║ Before ║ Now ║
╠═══════════════╬════════╬═══════╣
║ 0 == "foo" ║ true ║ false ║
║ 0 == "" ║ true ║ false ║
║ 42 == "42foo" ║ true ║ false ║
╚═══════════════╩════════╩═══════╝
Perbandingan Ketat
Masalah-masalah ini sulit ditemukan dalam kode, tetapi lebih baik mengetahuinya terlebih dahulu
Seperti disebutkan di atas, beberapa fungsi PHP bawaan beralih ke argumen yang diketik dengan ketat, dan perpustakaan pihak ketiga mendukung tren yang sama. Jika pengetikan yang ketat tidak digunakan dalam kode, semuanya akan tetap berfungsi dengan pengetikan dalam banyak kasus. Tapi ada pengecualian;
Misalnya, fungsi bulat tidak menerima argumen string yang tidak cocok dengan int. tanda tangan mengapung. Baris “40. 5” akan berfungsi tetapi “40. 5” tidak akan, atau sebaliknya, tergantung pada lokalnya
- $amount = round($row[$attributeName], 2);+ $amount = round((float)$row[$attributeName], 2);_
str_replace dengan menyatakan(strict_types=1) tidak lagi menerima integer sebagai argumen kedua karena mengharapkan sebuah array. rangkaian
- $alias = str_replace(WebsiteIdPlaceholder::NAME, $websiteId, $alias);+ $alias = str_replace(WebsiteIdPlaceholder::NAME, (string)$websiteId, $alias);
Tetapi ada juga kasus yang kurang jelas di mana perilaku berubah secara diam-diam. Dalam kasus kami, php-amqplib berhenti terhubung ke RabbitMQ karena kami meneruskan array kosong ke fungsi saat null diharapkan. Di versi sebelumnya, dengan perbandingan yang longgar, ini bekerja sangat berbeda
- $this->channel->wait([], false, $timeout);+ $this->channel->wait(null, false, $timeout);_
Argumen bernama
Kami mengalami masalah dari fitur yang agak kontradiktif ini bahkan sebelum kami mulai menggunakannya
Misalnya, sekarang Anda tidak dapat dengan aman meneruskan larik asosiatif dengan argumen ke call_user_func_array
- $data = call_user_func_array('array_merge', $indexData);+ $data = array_merge(...array_values($indexData));_
Kesalahan Alih-alih Mengembalikan Salah
Berikut adalah beberapa contoh perubahan pada kode kami
get_parent_class
"platform": {"php": "7.4"}_0metode_ada
"platform": {"php": "7.4"}_1Atau benar-benar menangkap kesalahan
"platform": {"php": "7.4"}_2Ini hanyalah perubahan wajib yang diperlukan saat memutakhirkan satu repositori dengan 3.000.000.000 baris kode PHP ke versi 8. 0, yang sedikit dijelaskan dalam dokumentasi. Anda dapat menemukan daftar lengkapnya di panduan pembaruan resmi
Hasil
Jadi berapa banyak baris kode yang harus kita perbarui di repositori Oro untuk mendukung PHP 8?. )
Seperti yang Anda lihat, pembaruannya cukup sederhana dan umumnya membantu menemukan kode yang bukan kualitas terbaik. Karena tujuannya adalah untuk mendukung PHP 8. 0 tanpa menggunakan fitur-fitur baru, dan pengembang berusaha mempertahankan kompatibilitas mundur, permintaan tarikan ternyata relatif kecil. 86 file dengan +316 dan 257 baris yang dimodifikasi. Ini tanpa memperhitungkan perubahan pada composer. json dan komposer. kunci
Permintaan penarikan kecil, terutama karena kami menyelesaikan sebagian besar pembaruan vendor tiga bulan lalu sebagai bagian dari persiapan rilis LTS. Proses pemutakhiran, tidak termasuk ulasan, memakan waktu sekitar 40 jam di seluruh repositori monolitik, yang relatif sedikit dibandingkan dengan pengalaman pembaruan teknologi sebelumnya di Oro. Tentu saja, perkiraannya akan bervariasi tergantung pada jumlah dan konten kode, tetapi karena sebagian besar proyek PHP sebagian besar tingkat tinggi, Anda seharusnya tidak menghadapi lebih banyak masalah daripada yang kami alami.
Apa berikutnya?Sekarang Anda dapat menggunakan semua fitur baru untuk meningkatkan keterbacaan kode — setidaknya dalam kode baru. Paling-paling, jika Anda tidak khawatir kehilangan kesalahan git, Anda dapat menggunakannya di seluruh proyek, berkat otomatisasi yang disediakan oleh Rektor dan alat serupa
Nyalakan JIT, silangkan jari, dan luncurkan ApacheBench
Dan tunggu PHP 8. 1 (yang akhirnya akan menyertakan enum), revolusi dari serat, dan ketika semua pemeriksaan jenis yang bekerja saat runtime di PHP akan memperlambat aplikasi lebih sedikit