هذا مقال قصير حول المشاكل المحتملة على الأرجح مع json_encode وحلولها. في بعض الأحيان ، عند تشفير البيانات في json ، باستخدام json_encode في php ، نحصل على النتيجة الخاطئة التي نتوقعها. أبرزت المشكلات الثلاث الأكثر شيوعًا التي يواجهها المبرمجون:
- الوصول إلى الحقول
- ترميز قيمة النص
- القيم العددية
الوصول إلى الحقول
المشكلة هي أن 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; } }
ثم ستكون نتيجة الكود التالي:
$obj = new Example("some", "value", "here"); echo json_encode($obj);
كما ترون ، تم تضمين الحقول العامة فقط في ملف json الناتج.
ماذا تفعل إذا كنت بحاجة إلى جميع الحقول؟
قرار
لـ php <5.4:
سنحتاج إلى تطبيق طريقة في الفصل ستعيد json النهائي. لأن داخل الفصل هناك الوصول إلى جميع الحقول ، يمكنك تشكيل التمثيل الصحيح للكائن 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, ]); } }
للحصول على json-a من كائن ما ، تحتاج الآن إلى استخدام الأسلوب toJson ، بدلاً من تطبيق json_encode مباشرة على الكائن
$obj = new Example("some", "value", "here"); echo $obj->toJson();
لـ php> = 5.4:
سيكون كافياً تطبيق واجهة JsonSerializable لفئتنا ، مما يعني إضافة طريقة jsonSerialize التي ستُرجع بنية تمثل كائن 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, ]; } }
الآن يمكننا استخدام json_encode كما كان من قبل
$obj = new Example("some", "value", "here"); echo json_encode($obj);
لماذا لا تستخدم النهج مع طريقة toJson؟
ربما لاحظ الكثيرون أنه يمكن استخدام طريقة إنشاء طريقة إرجاع json في إصدارات php> = 5.4. فلماذا لا تستفيد منه؟ الشيء هو أنه يمكن استخدام فصلك كجزء من بنية بيانات مختلفة.
echo json_encode([ 'status' => true, 'message' => 'some message', 'data' => new Example("some", "value", "here"), ]);
وستكون النتيجة بالفعل مختلفة تماما.
أيضًا ، يمكن استخدام الفئة بواسطة المبرمجين الآخرين ، والذين قد لا يكون هذا النوع من الحصول على json من كائن واضحًا تمامًا.
ماذا لو كان لدي الكثير من الحقول في الفصل؟
في هذه الحالة ، يمكنك استخدام الدالة 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);
وإذا كنت بحاجة إلى حقول خاصة من فئة لا يمكن تحريرها؟
قد ينشأ موقف عندما تحتاج إلى الحصول على حقول خاصة ( خاصة ، حيث يمكن الوصول إلى الحقول المحمية من خلال الميراث) في json. في هذه الحالة ، سيكون من الضروري استخدام الانعكاس:
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);
قيم النص الترميز
السيريلية وغيرها من علامات في UTF8
النوع الثاني من مشكلة json_encode الشائعة هو ترميز المشكلات. غالبًا ما تحتوي القيم النصية التي تحتاج إلى تشفير في json على أحرف في UTF8 (بما في ذلك السيريلية) ، ونتيجة لذلك ، سيتم تقديم هذه الأحرف في شكل رموز:
echo json_encode(" or ₳ ƒ 元 ﷼ ₨ ௹ ¥ ₴ £ ฿ $");
يتم التعامل مع عرض هذه الأحرف بكل بساطة - عن طريق إضافة علامة JSON_UNESCAPED_UNICODE كالوسيطة الثانية لوظيفة json_encode :
echo json_encode(" or ₳ ƒ 元 ﷼ ₨ ௹ ¥ ₴ £ ฿ $", JSON_UNESCAPED_UNICODE);
الرموز في الترميزات الأخرى
تعامل دالة json_encode قيم السلسلة كسلسلة في UTF8 ، والتي يمكن أن تسبب خطأ إذا كان الترميز مختلفًا. ضع في اعتبارك جزءًا صغيرًا من الكود (مثال هذا الكود بسيطًا قدر الإمكان لإظهار موقف مشكلة)
echo json_encode(["p" => $_GET['p']]);
للوهلة الأولى ، لا شيء ينذر بالمشاكل ، وما الخطأ الذي يمكن أن يحدث هنا؟ اعتقدت ذلك ايضا. في الغالبية العظمى من الحالات ، سينجح كل شيء ، ولهذا السبب ، استغرق العثور على المشكلة وقتًا طويلاً عندما واجهت لأول مرة نتيجة json_encode خاطئة.
لإعادة إنشاء هذا الموقف ، افترض أن p = ٪ EF٪ F2٪ E8٪ F6٪ E0 (على سبيل المثال: localhost؟ =٪ EF٪ F2٪ E8٪ F6٪ E0 ).
* المتغيرات في صفائف superglobal $ _GET و $ _REQUEST قد تم فك شفرتها بالفعل.
$decoded = urldecode("%EF%F2%E8%F6%E0"); var_dump(json_encode($decoded));
كما ترون من الخطأ: مشكلة ترميز السلسلة المنقولة (هذه ليست UTF8). حل المشكلة واضح - جلب القيمة إلى UTF8
$decoded = urldecode("%EF%F2%E8%F6%E0"); $utf8 = utf8_encode($decoded); echo json_encode($utf8);
القيم العددية
يرتبط الخطأ النموذجي الأخير بترميز القيم العددية.
على سبيل المثال:
echo json_encode(["string_float" => "3.0"]);
كما تعلمون ، php ليست لغة مكتوبة بدقة وتسمح لك باستخدام الأرقام كسلسلة ، وفي معظم الحالات لا يؤدي هذا إلى أخطاء داخل تطبيق php. ولكن نظرًا لأن json يستخدم غالبًا لنقل الرسائل بين التطبيقات ، فإن هذا التنسيق لكتابة الأرقام يمكن أن يسبب مشاكل في تطبيق آخر. يُنصح باستخدام علامة JSON_NUMERIC_CHECK :
echo json_encode(["string_float" => "3.0"], JSON_NUMERIC_CHECK);
بالفعل أفضل. ولكن كما ترون ، تحول "3.0" إلى 3 ، والتي سيتم تفسيرها في معظم الحالات على أنها int. نستخدم علامة أخرى JSON_PRESERVE_ZERO_FRACTION لتحويل صحيح إلى تعويم:
echo json_encode(["string_float" => "3.0"], JSON_NUMERIC_CHECK | JSON_PRESERVE_ZERO_FRACTION);
أطلب منك أيضًا الانتباه إلى جزء التعليمات البرمجية التالي ، والذي يوضح عددًا من المشكلات المحتملة في json_encode والقيم العددية:
$data = [ "0000021",
شكرا للقراءة.
سيسعدني أن أرى في التعليقات وصفًا للمشاكل التي واجهتها والتي لم يتم ذكرها في المقالة