Bagaimana PHP mewakili string secara internal?

18

UTF8?
UTF16?

Apakah string dalam PHP juga melacak pengodean yang digunakan?

Mari kita lihat skrip ini sebagai contoh. Katakanlah saya menjalankan:

$original = "शक्नोम्यत्तुम्";

Apa yang sebenarnya terjadi?

Jelas saya pikir $originaltidak akan berisi hanya 7 karakter. Mesin terbang masing-masing harus diwakili oleh beberapa byte di sana.

Maka saya lakukan:

$converted = mb_convert_encoding ($original , "UTF-8");

Apa yang akan terjadi $converted? Bagaimana $convertedperbedaannya $original?

Apakah hanya urutan byte yang sama persis $originaltetapi dengan pengkodean yang berbeda?

pengguna4951
sumber
1
Versi PHP yang mana? PHP <6 tidak dapat menangani UTF-8 asli. Ada beberapa paket dan metode yang membantu / menyelesaikan masalah ini. Google bersenang-senang dengan utf-8 dan php. Kemudian beralihlah ke platform lain alih-alih PHP. :)
Andrew T Finnell
4
PHP <6? Itu akan mencakup setiap versi PHP yang pernah dirilis ...
tdammers
1
Juga, PHP dapat menangani UTF-8, hanya saja tidak memiliki tipe data khusus, jadi Anda harus melihat apa yang Anda lakukan.
tammmer

Jawaban:

22

Sebuah string PHP hanyalah urutan byte, tanpa pengkodean yang ditandai untuk itu. Nilai string dapat berasal dari berbagai sumber: klien (melalui HTTP), database, file, atau dari string literal dalam kode sumber Anda. PHP membaca semua ini sebagai urutan byte, dan tidak pernah mengekstrak informasi pengodean apa pun.

Selama semua sumber data dan tujuan Anda menggunakan penyandian yang sama, hal terburuk yang dapat terjadi adalah bahwa posisi string salah (jika Anda menggunakan penyandian multi-byte), karena PHP akan menghitung byte, bukan karakter.

Tetapi jika pengkodean tidak cocok (misalnya Anda menulis string literal dalam file sumber yang disimpan sebagai UTF-8, dan kemudian mengirimnya ke database yang mengharapkan Latin-1), PHP tidak akan melakukan konversi untuk Anda: itu akan dengan senang hati menyalin byte di atas mentah.

Solusi terbaik adalah ini:

  • Atur pengodean internal PHP ke UTF-8.
  • Simpan semua file sumber Anda sebagai UTF-8.
  • Gunakan UTF-8 sebagai penyandian keluaran Anda (jangan lupa untuk mengirim Content-typetajuk yang sesuai ).
  • Atur koneksi database untuk menggunakan UTF-8 ( SET NAMES UTF8di MySQL).
  • Konfigurasikan yang lainnya menjadi UTF-8 jika memungkinkan.
  • Untuk apa pun yang tidak dapat Anda kontrol (mis. Layanan web pihak ketiga), pastikan Anda mengetahui penyandian, dan mengonversi ke UTF-8 sedini mungkin, dan kembali ke penyandian lain selambat mungkin.

Mengapa UTF-8? Karena itu dapat mewakili semua karakter Unicode dan dengan demikian menggantikan semua pengkodean 7-bit dan 8-bit yang ada, dan karena itu adalah biner yang kompatibel dengan ASCII, yaitu, setiap string ASCII yang valid juga merupakan string UTF-8 yang valid (tetapi tidak vv .).

Dalam contoh Anda, apa yang terjadi adalah ini.

Pertama, Anda menyimpan file sumber Anda; editor teks Anda mungkin dikonfigurasikan untuk menggunakan UTF-8, jadi string literal Anda berakhir dengan UTF-8 yang disandikan pada disk. PHP membaca file ini, menafsirkan string sebagai serangkaian byte; $originalsekarang memegang string yang dikodekan UTF-8 dengan 7 karakter, yang hanya merupakan urutan byte (meskipun berisi lebih dari 7 byte, karena setiap karakter diwakili oleh dua atau lebih byte). Jika Anda menelepon echo $original, string yang disandikan dikirim ke klien apa adanya; jika Anda telah memberitahu klien untuk mengharapkan UTF-8, semuanya baik-baik saja, tetapi jika Anda belum, PHP tidak memiliki cara untuk membedakannya, dan Anda akan berakhir dengan sampah di browser. Sebagai percobaan, coba ini:

$original = "शक्नोम्यत्तुम्";
echo strlen($original);

strlen adalah pengkodean-agnostik dan mengasumsikan pengodean 8 bit dengan lebar tetap, yaitu, satu byte per karakter, sehingga akan menghitung byte, bukan karakter.

tammmer
sumber
Jadi $ dikonversi akan mewakili string yang sama tetapi dalam pengkodean lainnya. Pengkodean mentah yang sebenarnya, yang merupakan penyimpanan PhP, akan berbeda.
user4951
2
Saya akan mengulanginya untuk Anda: PHP menyimpan byte, bukan karakter, dan tidak tahu sama sekali tentang penyandian (meskipun beberapa fungsi perpustakaan melakukannya.
tdammers
1
Oh, dan itu "PHP", bukan "PhP".
tdammers
2
jika byte mentah adalah sama, apa perbedaan antara $ original dan $ dikonversi maka. Itulah yang saya minta.
user4951
2
Oh, baiklah, itu yang kamu maksud. Ya, byte mentah berubah sesuai dengan konversi pengkodean. PHP tidak ingat pengkodeannya, jadi jika Anda mengubah string dari, katakanlah, utf-8 ke latin-1, dan kemudian perlakukan hasilnya sebagai utf-8, Anda akan melihat hasil yang aneh.
tdammers