Ini adalah artikel singkat tentang masalah yang paling mungkin terjadi dengan json_encode dan solusinya. Terkadang saat meng-enkode data dalam json, menggunakan json_encode di php, kami mendapatkan hasil yang salah yang kami harapkan. Saya menyoroti tiga masalah paling umum yang dihadapi programmer:
- akses ke bidang
- pengkodean nilai teks
- nilai numerik
Akses ke bidang
Masalahnya adalah bahwa json_encode hanya memiliki akses ke bidang publik objek. Misalnya, jika Anda memiliki kelas
class Example { public $publicProperty; protected $protectedProperty; private $privateProperty; public function __construct($public, $protected, $private) { $this->publicProperty = $public; $this->protectedProperty = $protected; $this->privateProperty = $private; } }
maka hasil dari kode berikut adalah:
$obj = new Example("some", "value", "here"); echo json_encode($obj);
seperti yang Anda lihat, hanya bidang publik yang dimasukkan dalam json yang dihasilkan.
Apa yang harus dilakukan jika Anda membutuhkan semua bidang?
Solusi
Untuk php <5.4:
kita perlu mengimplementasikan metode di kelas yang akan mengembalikan json yang sudah selesai. Karena di dalam kelas ada akses ke semua bidang, Anda dapat membentuk representasi objek yang benar untuk json_encode
class Example { public $publicProperty; protected $protectedProperty; private $privateProperty; public function __construct($public, $protected, $private) { $this->publicProperty = $public; $this->protectedProperty = $protected; $this->privateProperty = $private; } public function toJson() { return json_encode([ 'publicProperty' => $this->publicProperty, 'protectedProperty' => $this->protectedProperty, 'privateProperty' => $this->privateProperty, ]); } }
Untuk mendapatkan json-a dari objek, Anda sekarang perlu menggunakan metode toJson , daripada langsung menerapkan json_encode ke objek
$obj = new Example("some", "value", "here"); echo $obj->toJson();
Untuk php> = 5.4:
itu akan cukup untuk mengimplementasikan antarmuka JsonSerializable untuk kelas kita, yang menyiratkan menambahkan metode jsonSerialize yang akan mengembalikan struktur yang mewakili objek untuk json_encode
class Example implements JsonSerializable { public $publicProperty; protected $protectedProperty; private $privateProperty; public function __construct($public, $protected, $private) { $this->publicProperty = $public; $this->protectedProperty = $protected; $this->privateProperty = $private; } public function jsonSerialize() { return [ 'publicProperty' => $this->publicProperty, 'protectedProperty' => $this->protectedProperty, 'privateProperty' => $this->privateProperty, ]; } }
Sekarang kita bisa menggunakan json_encode seperti sebelumnya
$obj = new Example("some", "value", "here"); echo json_encode($obj);
Mengapa tidak menggunakan pendekatan dengan metode toJson?
Banyak yang mungkin memperhatikan bahwa pendekatan untuk menciptakan metode mengembalikan json dapat digunakan dalam versi php> = 5.4. Jadi mengapa tidak memanfaatkannya? Masalahnya adalah bahwa kelas Anda dapat digunakan sebagai bagian dari struktur data yang berbeda.
echo json_encode([ 'status' => true, 'message' => 'some message', 'data' => new Example("some", "value", "here"), ]);
dan hasilnya akan sangat berbeda.
Juga, kelas dapat digunakan oleh programmer lain, untuk siapa jenis ini mendapatkan json dari suatu objek mungkin tidak sepenuhnya jelas.
Bagaimana jika saya memiliki banyak bidang di kelas?
Dalam hal ini, Anda dapat menggunakan fungsi get_object_vars
class Example implements JsonSerializable { public $publicProperty; protected $protectedProperty; private $privateProperty; protected $someProp1; ... protected $someProp100500; public function __construct($public, $protected, $private) { $this->publicProperty = $public; $this->protectedProperty = $protected; $this->privateProperty = $private; } public function jsonSerialize() { $fields = get_object_vars($this);
Dan jika Anda membutuhkan bidang pribadi dari kelas yang tidak dapat diedit?
Situasi mungkin muncul ketika Anda perlu mendapatkan bidang pribadi ( pribadi , karena akses ke bidang yang dilindungi dapat diperoleh melalui warisan) di json. Dalam hal ini, perlu menggunakan refleksi:
class Example { public $publicProperty = "someValue"; protected $protectedProperty; private $privateProperty1; private $privateProperty2; private $privateProperty3; public function __construct($privateProperty1, $privateProperty2, $privateProperty3, $protectedProperty) { $this->protectedProperty = $protectedProperty; $this->privateProperty1 = $privateProperty1; $this->privateProperty2 = $privateProperty2; $this->privateProperty3 = $privateProperty3; } } $obj = new Example("value1", 12, "21E021", false); $reflection = new ReflectionClass($obj); $public = []; foreach ($reflection->getProperties() as $property) { $property->setAccessible(true); $public[$property->getName()] = $property->getValue($obj); } echo json_encode($public);
Pengkodean Nilai Teks
Sirilik dan tanda-tanda lain di UTF8
Tipe kedua dari masalah json_encode yang umum adalah masalah penyandian. Seringkali nilai teks yang perlu dikodekan dalam json memiliki karakter dalam UTF8 (termasuk Cyrillic), sebagai akibatnya, karakter ini akan disajikan dalam bentuk kode:
echo json_encode(" or ₳ ƒ 元 ﷼ ₨ ௹ ¥ ₴ £ ฿ $");
Tampilan karakter tersebut diperlakukan sangat sederhana - dengan menambahkan flag JSON_UNESCAPED_UNICODE sebagai argumen kedua ke fungsi json_encode :
echo json_encode(" or ₳ ƒ 元 ﷼ ₨ ௹ ¥ ₴ £ ฿ $", JSON_UNESCAPED_UNICODE);
Simbol dalam penyandian lainnya
Fungsi json_encode memperlakukan nilai string sebagai string dalam UTF8, yang dapat menyebabkan kesalahan jika pengkodeannya berbeda. Pertimbangkan sepotong kecil kode (contoh kode ini sesederhana mungkin untuk menunjukkan situasi masalah)
echo json_encode(["p" => $_GET['p']]);
Sekilas, tidak ada yang menandakan masalah, dan apa yang salah di sini? Saya juga berpikir begitu. Dalam sebagian besar kasus, semuanya akan bekerja, dan untuk alasan ini, menemukan masalah itu membuat saya sedikit lebih lama ketika saya pertama kali menemukan hasil json_encode salah.
Untuk membuat ulang situasi ini, anggaplah bahwa p = % EF% F2% E8% F6% E0 (misalnya: localhost? =% EF% F2% E8% F8% F6% E0 ).
* Variabel dalam array superglobal $ _GET dan $ _REQUEST sudah diterjemahkan.
$decoded = urldecode("%EF%F2%E8%F6%E0"); var_dump(json_encode($decoded));
Seperti yang Anda lihat dari kesalahan: masalah dengan pengkodean dari string yang ditransmisikan (ini bukan UTF8). Solusi untuk masalah ini sudah jelas - bawa nilainya ke UTF8
$decoded = urldecode("%EF%F2%E8%F6%E0"); $utf8 = utf8_encode($decoded); echo json_encode($utf8);
Nilai numerik
Kesalahan tipikal terakhir terkait dengan pengkodean nilai numerik.
Sebagai contoh:
echo json_encode(["string_float" => "3.0"]);
Seperti yang Anda ketahui, php bukan bahasa yang diketik dengan ketat dan memungkinkan Anda untuk menggunakan angka sebagai string, dalam banyak kasus ini tidak menyebabkan kesalahan di dalam aplikasi php. Tetapi karena json sangat sering digunakan untuk mentransfer pesan antar aplikasi, format penulisan angka ini dapat menyebabkan masalah pada aplikasi lain. Dianjurkan untuk menggunakan bendera JSON_NUMERIC_CHECK :
echo json_encode(["string_float" => "3.0"], JSON_NUMERIC_CHECK);
Sudah lebih baik. Tetapi seperti yang Anda lihat, "3.0" berubah menjadi 3, yang dalam banyak kasus akan ditafsirkan sebagai int. Kami menggunakan satu lagi flag JSON_PRESERVE_ZERO_FRACTION untuk konversi yang benar ke float:
echo json_encode(["string_float" => "3.0"], JSON_NUMERIC_CHECK | JSON_PRESERVE_ZERO_FRACTION);
Saya juga meminta Anda untuk memperhatikan fragmen kode berikut, yang menggambarkan sejumlah kemungkinan masalah dengan json_encode dan nilai numerik:
$data = [ "0000021",
Terima kasih sudah membaca.
Saya akan senang melihat di komentar deskripsi masalah yang Anda temui yang tidak disebutkan dalam artikel