Kode

<?php
$consts = get_defined_constants();
$consts = array_keys($consts);
usort($consts,function($a,$b){return (int)(strlen($a)<strlen($b));});
foreach($consts as $const){
    echo strlen($const).": ".$const."\n";
}

Akan, sebelum PHP 8.0.0, mencetak semua konstanta yang ditentukan dari terpanjang ke terpendek, seperti yang saya harapkan. 7.3.13 dimulai dengan

62: SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_INTERACTIVE
62: SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE
60: SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_SENSITIVE
60: SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_SENSITIVE
51: SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_STRPREFIX

Tapi saya tidak tahu apa yang dilakukan PHP8.0.0, outputnya dimulai dengan:

9: E_WARNING
21: FILTER_FLAG_STRIP_LOW
7: E_ERROR
26: FILTER_FLAG_STRIP_BACKTICK

Anda dapat melihatnya sendiri di 3v4l: https://3v4l.org/MP2IF

Jadi apa yang terjadi di PHP 8.0.0 untuk memecahkan kode ini?

4
hanshenrik 20 Desember 2020, 20:33

3 jawaban

Jawaban Terbaik

Sebagian besar jawaban lain di sini difokuskan pada cara memperbaiki masalah, tetapi saya pikir saya akan mencoba dan menjelaskan mengapa ini berubah di PHP 8, yang menurut saya itulah yang Anda minati.

PHP 8 memperkenalkan RFC Penyortiran Stabil, yang (seperti yang terdengar) berarti bahwa semua fungsi penyortiran di PHP sekarang "stabil". Lebih detail tentang ini di tautan.

Jawaban lain sudah membahas ini dengan baik, tetapi fungsi Anda mengembalikan nol atau angka yang lebih besar dari nol. Implementasi penyortiran sebelumnya di PHP (di semua versi yang lebih rendah dari 8) dianggap nol dan angka negatif sama; seperti yang disebutkan RFC di atas, cek itu hanya untuk angka yang lebih besar dari nol, atau tidak. Mengembalikan nol berarti bahwa elemen-elemen ini diperlakukan sama seperti kasus di mana $a < $b.

PHP memperkenalkan peringatan penghentian sehingga banyak implementasi pengurutan yang mengembalikan boolean masih akan berfungsi. RFC memberikan beberapa detail lebih lanjut tentang ini, tetapi yang terpenting itu berarti PHP 8 masih kompatibel dengan mereka (karenanya ini adalah pemberitahuan penghentian, bukan peringatan). Kasus tepi di sini adalah bahwa sementara fungsi Anda secara efektif mengembalikan boolean - 0 untuk panjang yang sama, dan 1 untuk kasus di mana $a < $b - karena Anda memasukkan ini ke bilangan bulat, pemeriksaan kompatibilitas mundur di PHP 8 tidak tidak menangkapnya, sehingga semua elemen "sama" dianggap seolah-olah $a < $b

Membandingkan:

function($a, $b) { return (int) (strlen($a) < strlen($b)); }

Seperti pada pertanyaan - berfungsi dengan benar di PHP <8, tetapi tidak menimbulkan pemberitahuan penghentian. https://3v4l.org/MP2IF


function($a, $b) { return strlen($a) < strlen($b); }

Mengembalikan boolean, sehingga pemeriksaan kompatibilitas mundur di PHP 8 berfungsi dengan benar. Tapi pemberitahuan penghentian sekarang dinaikkan. https://3v4l.org/fWR2Y


function($a, $b) { return strlen($b) <=> strlen($a); }

Solusi "benar", bekerja dengan benar di semua versi (setidaknya sejak operator pesawat ruang angkasa diperkenalkan). https://3v4l.org/6XRYW

5
iainn 20 Desember 2020, 21:29

Saya tidak tahu apa yang berubah secara internal yang menyebabkan perbedaan ini, tetapi panggilan balik penyortiran Anda agak funky. Seharusnya hanya mengembalikan 0 jika $a dan $b secara fungsional "sama" (dalam hal ini, jika mereka memiliki panjang string yang sama). Kalau tidak, itu harus mengembalikan 1 jika $a harus diurutkan sebelum $b, atau -1 sebaliknya. Jika saya mengubah panggilan balik Anda dengan tepat, saya mendapatkan hasil yang diharapkan.

usort($consts, function($a, $b) {
    $aLen = strlen($a);
    $bLen = strlen($b);
    if ($aLen === $bLen) {
        return 0;
    }
    return $aLen < $bLen ? 1 : -1;
});

3v4l: https://3v4l.org/UScFO

2
Garrett Albright 20 Desember 2020, 17:55

Itu karena Anda mengembalikan 0 atau 1, bukan -1. Anda harus menggunakan operator pesawat ruang angkasa sebagai gantinya: https://3v4l.org/PLYAP

usort($consts, function($a, $b) {
    return strlen($b) <=> strlen($a);
});

0 harus dikembalikan jika kedua belah pihak sama.

2
HTMHell 20 Desember 2020, 17:55