jsonobject
jsonobject
هي فئة PHP لتسهيل استخدام الكائنات القادمة من تعريف JSON. تأتي الفكرة من استخدام pydantic
في لغة python، وقدرته على تحليل بيانات json والتحقق من صحتها وتحويلها إلى كائنات.
jsonobject
اضطررت إلى استخدام واجهة برمجة التطبيقات من PHP، وقد أعادتني واجهة برمجة التطبيقات تلك إلى jsonobject s. لذلك كنت بحاجة إلى تحليلها إلى كائنات PHP التي تمكنت من استخدامها في التطبيق.
سير العمل هو
jsonobject
لتحليل تعريف JSONلنأخذ مثال JSON التالي:
{
"id" : 0 ,
"name" : " John Doe " ,
"age" : 42 ,
"emails" : [
" [email protected] " ,
" [email protected] "
],
"address" : {
"street" : " My street " ,
"number" : 42 ,
"city" : " My city " ,
"country" : " My country "
}
}
باستخدام jsonobject
، سأتمكن من تحديد نموذج البيانات الخاص بي باستخدام الفئات التالية:
class User extends jsonobject {
const ATTRIBUTES = [
' id ' => ' int ' ,
' name ' => ' str ' ,
' age ' => ' int ' ,
' emails ' => ' list[str] ' ,
' address? ' => ' Address ' ,
];
}
class Address extends jsonobject {
const ATTRIBUTES = [
' street ' => ' str ' ,
' number ' => ' int ' ,
' city ' => ' str ' ,
' country ' => ' str ' ,
];
}
ثم قم بإضافة الأمر التالي:
$ user = User:: fromObject ( json_decode ( $ json_text_definition ));
ستقوم فئة jsonobject
بتحليل المحتوى إلى كائنات، وسنكون قادرين على استخدام سماتها على النحو المحدد:
echo ( $ user -> name );
يمكن أن تحتوي الفئات المحددة أيضًا على طرق تسهل تنفيذ نموذج بيانات التطبيق. على سبيل المثال، من الممكن تحديد فئة User
مثل هذا:
class User extends jsonobject {
const ATTRIBUTES = [
' id ' => ' int ' ,
' name ' => ' str ' ,
' age ' => ' int ' ,
' emails ' => ' list[str] ' ,
' address? ' => ' Address ' ,
];
public function isAdult () {
return $ this -> age >= 18 ;
}
}
jsonobject
فكرة فئة jsonobject
هي استخدامها لتحليل بيانات json إلى كائنات. بحيث قد تحتوي هذه الكائنات على طرق أخرى تساعد في تنفيذ نموذج بيانات التطبيق.
عندما يتم تحليل كائن (أو مصفوفة) json، يتم تحليل محتواه بشكل متكرر وفقًا للأنواع المحددة في ثابت ATTRIBUTES
. إذا كانت البيانات غير صالحة، لأنها لا تحتوي على القيم المتوقعة، فسيتم طرح استثناء.
لاستخدام jsonobject يجب على المرء فئة فرعية jsonobject
وتحديد ثابت ATTRIBUTES
لتلك الفئة بحيث يحدد السمات المتوقعة لكائنات تلك الفئة، بالإضافة إلى نوع كل منها.
ثابت ATTRIBUTES
هو مصفوفة ترابطية حيث المفاتيح هي اسم كل سمة ، والقيم هي نوع كل سمة .
الأنواع المحتملة يمكن أن تكون:
jsonobject
. عند تحديد اسم السمات، يمكن إضافة ?
في نهاية الاسم للإشارة إلى أن السمة اختيارية. على سبيل المثال، address?
في قسم حالة الاستخدام اختياري.
يعتبر كل حقل إلزاميًا بحيث يجب أن يكون موجودًا في الكائن (أو الصفيف) الذي تم تحليله. علاوة على ذلك، يجب أن يكون الكائن من النوع المحدد (أي يجب تحليله بشكل صحيح حسب النوع المحدد).
وأي صفة غير اختيارية تعتبر جبرية. وهذا يهم بشكل خاص نقطتين:
fromArray
أو fromObject
).jsonobject
عند إنشاء الكائن من بنية خارجية، سيهتم jsonobject
بكل حقل إلزامي. وإذا فقد أي منهم، سيتم رفع استثناء.
في المثال التالي، سيتم طرح استثناء لأنه لم يتم توفير عمر الحقل الإلزامي.
class User extends jsonobject {
const ATTRIBUTES = [
" name " => " str " ,
" age " => " int " ,
];
}
( . . . )
$ user = User:: fromArray ([ " name " => " John " ]);
عند تحويل الكائن إلى مصفوفة أو إلى كائن (أو الحصول على تمثيل json الخاص به)، سيحصل الحقل الإلزامي على قيمة افتراضية، حتى لو لم يتم تعيينه.
لذلك في المثال التالي
class User extends jsonobject {
const ATTRIBUTES = [
" name " => " str " ,
" age " => " int " ,
" birthDate? " => " str "
];
}
$ user = new User ();
echo (( string ) $ user );
سيكون الناتج
{
"name" : " " ,
"age" : 0
}
لأنه على الرغم من أن اسم السمات وعمرها إلزاميان ويحصلان على قيمهما الافتراضية (أي 0 للأرقام، وفارغة للسلاسل أو القوائم أو الإملاءات)، فإن تاريخ ميلاد السمة ليس إلزاميًا ولم يتم تعيينه بعد. لذلك لا يتم إنشاؤه في الإخراج.
null
على السمات الإلزاميةتعتبر مشكلة تعيين القيم إلى قيمة خالية ذات أهمية خاصة عند النظر فيما إذا كانت السمة اختيارية أم لا.
قد يعتقد المرء أنه إذا قمنا بتعيين قيمة على أنها خالية ، فهذا يعني إلغاء تعيين القيمة وبالتالي يجب أن يكون ذلك ممكنًا فقط للقيم الاختيارية ولكن ليس للقيم الإلزامية.
في jsonobject
لدينا مفهوم مختلف، لأن تعيين الخاصية على null يعني "تعيين القيمة على null " وعدم إلغاء تعيين الخاصية. من أجل إلغاء تعيين الخاصية، يجب علينا استخدام وظيفة unset أو شيء من هذا القبيل.
يتيح jsonobject
أيضًا إلغاء تعيين القيم. بالنسبة للسمة الاختيارية، فهذا يعني إزالة القيمة وبالتالي لن يكون لها أي قيمة في تمثيل المصفوفة أو الكائن (إذا تم استرداد القيمة، فسيتم تعيينها على null ).
لكن بالنسبة للسمة الإلزامية، فإن إلغاء ضبطها يعني إعادة تعيين قيمتها إلى القيمة الافتراضية . وهذا يعني أنه ستتم تهيئته إلى القيمة الافتراضية للنوع (أي 0 للأرقام، أو فارغ للقوائم، أو السلاسل أو الإملاء، وما إلى ذلك) أو قيمته الافتراضية في ثابت ATTRIBUTES
.
jsonobject
s أيضًا قادرة على وراثة السمات من فئاتها الأصلية. خذ المثال التالي:
class Vehicle extends jsonobject {
const ATTRIBUTES = [
" brand " => " str " ,
" color " => " str "
]
}
class Car extends Vehicle {
const ATTRIBUTES = [
" wheels " => " int "
]
}
class Boat extends Vehicle {
const ATTRIBUTES = [
" length " => " float "
]
}
في هذا المثال، ستحتوي فئة Vehicle
فقط على سمات العلامة التجارية واللون ، ولكن ستحتوي فئة Car
على سمات العلامة التجارية واللون والعجلات ، بينما ستحتوي فئة Boat
على سمات العلامة التجارية واللون والطول .
يمكن إنشاء الكائنات من الفئات الفرعية لكائن jsonobject
باستخدام الطريقة الثابتة ::fromArray
أو ::fromObject
، بدءًا من كائن json الذي تم تحليله.
في المثال السابق، إذا كان لدينا ملف car.json بالمحتوى التالي:
{
"brand" : " BMW " ,
"color" : " black "
}
يمكننا استخدام الكود التالي للحصول على مثيل لفئة Vehicle
:
$ json = file_get_contents ( " car.json " );
$ vehicle = Vehicle:: fromArray (( array ) json_decode ( $ json , true ));
البديل هو إنشاء كائنات كما في المثال التالي
* PHP 8 وما فوق:
$ car = new Car (brand: " BMW " , color: " black " , wheels: 4 );
* إصدارات PHP السابقة:
$ car = new Car ([ " brand " => " BMW " , " color " => " black " , " wheels " => 4 ]);
jsonobject
jsonobject
هو الفئة الأساسية لهذه المكتبة. وأساليبها هي:
__construct($data)
- إنشاء كائن جديد من البيانات المعطاة__get($name)
- يُرجع قيمة السمة بالاسم المحدد__set($name, $value)
- يضبط قيمة السمة بالاسم المحدد__isset($name)
- يُرجع صحيحًا إذا تم تعيين السمة بالاسم المحدد__unset($name)
- يلغي قيمة السمة الاختيارية (أو يعيد تعيين قيمة السمة الإلزامية).toArray()
- يُرجع مصفوفة ترابطية تحتوي على بيانات الكائن. يتم إنشاء المصفوفة بشكل متكرر، وزيارة كل من السمات الفرعية لكل سمة.toObject()
- تقوم بإرجاع كائن مع بيانات الكائن كسمات. يتم إنشاء المصفوفة بشكل متكرر، وزيارة كل من السمات الفرعية لكل سمة.toJson()
- يُرجع سلسلة json مع تمثيل الكائن ككائن قياسي.::fromArray($data)
- ينشئ كائنًا عن طريق تحليل المصفوفة الترابطية المحددة في السمات المحددة في الفئة. يتم تحليل كل سمة بشكل متكرر، وفقًا للنوع المحدد لها.::fromObject($data)
- إنشاء كائن، عن طريق تحليل الكائن المحدد إلى السمات المحددة في الفئة. يتم تحليل كل سمة بشكل متكرر، وفقًا للنوع المحدد لها. JsonDict
يُستخدم هذا الكائن للتعامل مع قاموس قادم من تعريف json. تتم كتابة فئة JsonDict
بحيث يجب أن يكون كل عنصر من نوع معين.
يمكن استخدام كائنات JsonDict
ككائنات تشبه المصفوفة (على سبيل المثال $jsonDict["key1"]) ولكن (في لحظة كتابة هذا النص) لم يتم تحديد نوع العناصر المدرجة في القاموس. يتم استخدام النوع لتحليل المحتوى عند إنشاء الإملاء (على سبيل المثال باستخدام وظيفة fromArray
الثابتة) أو لتفريغ المحتوى إلى مصفوفة أو كائن (على سبيل المثال باستخدام وظيفة toArray
).
الطرق هي:
toArray()
toObject()
::fromArray($data)
::fromObject($data)
يتم تفسير هذه الأساليب بنفس الطريقة المستخدمة في حالة jsonobject
. وقد يشير نوع العناصر الموجودة في الإملاء إلى أنواع معقدة سيتم أخذها في الاعتبار بشكل متكرر عند تحليل المحتوى.
على سبيل المثال، سيتم استخدام list[list[int]]
لتحليل [ [ 1, 2, 3], [ 4, 5, 6 ]]
JsonArray
هذا الكائن يشبه إلى حد كبير JsonDict
باستثناء أن الفهارس يجب أن تكون أرقامًا صحيحة. في هذه الحالة، سيؤدي $value["key1"]
إلى إنشاء استثناء.
في هذه الحالة، يتم أيضًا تنفيذ وظيفة إلحاق العناصر بالمصفوفة (أي []
) .
عند تعريف الفئة، من الممكن تهيئة القيم للكائنات التي تم إنشاؤها حديثًا وتلك السمات الاختيارية.
هناك طريقتان:
### استخدام خصائص الفصل
من الممكن تهيئة قيمة كائن باستخدام خصائص الفئة، لذلك إذا تم تعيين قيمة سمة في الفئة، فسيتم نسخها إلى المثيل كسمة، إذا تم تعريفها.
على سبيل المثال
class User extends jsonobject {
const ATTRIBUTES = [
' id ' => ' int ' ,
' name ' => ' str ' ,
' age ' => ' int ' ,
' emails ' => ' list[str] ' ,
' address? ' => ' Address ' ,
' sex? ' => ' str '
];
public $ sex = " not revealed " ;
}
الآن، تتم تهيئة السمة sex
بحيث لا يتم الكشف عنها بدلاً من كونها null .
طريقة القيام بذلك هي تحديد صف [ <type>, <default value> ]
لنوع الكائن. خذ المثال التالي:
class User extends jsonobject {
const ATTRIBUTES = [
' id ' => ' int ' ,
' name ' => ' str ' ,
' age ' => ' int ' ,
' emails ' => ' list[str] ' ,
' address? ' => ' Address ' ,
' sex? ' => [ ' str ' , ' not revealed ' ]
];
}
يعتبر sex
السمة اختياريًا عند استرداد بيانات المستخدم. باستخدام هذا التعريف الجديد للفئة، إذا لم يتم تعيين sex
، فسيتم تعيين القيمة على "لم يتم الكشف عنها" بدلاً من null
.
الميزة المهمة هي أنه إذا كانت السلسلة التي تم تعيينها كـ <قيمة افتراضية> تتوافق مع طريقة الكائن، فسيتم استدعاؤها عند الحصول على القيمة (إذا لم يتم تعيينها بعد)، وسيتم تعيين القيمة لتلك الخاصية تكون نتيجة المكالمة.
على سبيل المثال
class User extends jsonobject {
const ATTRIBUTE = [
...
' birthDay? ' => [ ' str ' , ' computeBirthDate ' ]
]
function computeBirthDate () {
$ now = new DateTime ();
$ now ->sub( DateInterval ::createFromDateString("{ $ this -> age } years"));
return $ now ->format("Y-m-d");
}
}
في هذا المثال، إذا لم نقم بتعيين خاصية birthDate
ولكن تم استردادها، فسيتم حسابها عن طريق طرح العمر إلى التاريخ الحالي.
إذا أردت تحليل كائن عشوائي إلى jsonobject
، فمن الممكن استخدام الدالة jsonobject ::parse_typed_value
. يعد هذا أمرًا مهمًا لتتمكن من التحويل من أي نوع إلى نوع jsonobject
.
على سبيل المثال
$ myobject = jsonobject :: parse_typed_value ( " list[str] " , [ " my " , " name " , " is " , " John " ]);
سيتم الحصول على كائن من النوع JsonList<str>
.
السلوك الافتراضي لهذه المكتبة هو التأكد من أن القيم المحددة للسمات تتطابق مع نوعها المحدد. ولكن هذا يعني أنه نظرًا لأن float
ليس عددًا int
، فإن تعيين float على 0
سيفشل لأن 0
عدد صحيح. في هذه الحالة، يجب على المستخدم إرسال القيم قبل تعيينها. للتحكم في ما إذا كان سيتم التحقق من النوع بدقة أم لا، من الممكن استخدام الثابت STRICT_TYPE_CHECKING
.
إذا تم ضبط
STRICT_TYPE_CHECKING
علىTrue
، فسيتم فحص الأنواع بدقة، على سبيل المثال، سيؤدي تعيين9.3
إلىint
إلى ظهور استثناء. إذا تم التعيين علىFalse
، فسيتم تحويل الأنواع الرقمية من نوع إلى آخر. لذا، على سبيل المثال، إذا قمنا بتعيين9.3
إلىint
فسيتم اقتطاعه تلقائيًا إلى9
.
يتم التحقق من النوع المهم الآخر عند تعيين قيمة فارغة (على سبيل المثال ""
أو null
) لنوع رقمي. في هذه الحالة، لدينا الثابت STRICT_TYPE_CHECKING_EMPTY_ZERO
.
إذا تم تعيين
STRICT_TYPE_CHECKING_EMPTY_ZERO
علىTrue
(السلوك الافتراضي)، عند تعيين قيمة فارغة لنوع رقمي، فسيتم اعتبارها0
. أي أن تعيين سلسلة فارغة أو قيمةnull
إلى سمةint
، يعني تعيين0
. إذا تم التعيين علىFalse
، فستقوم المكتبة بالتحقق من الأنواع وستقوم في النهاية برفع استثناء.
الآن يتيح JsonList
أيضًا استخدام الفهارس السالبة، بحيث يكون -1
هو العنصر الأخير، -2
هو العنصر قبل الأخير، وما إلى ذلك.
يتضمن كائن JsonList
وظائف الفرز أو التصفية.
public function sort(callable $callback = null) : JsonList
: يقوم بفرز القائمة باستخدام رد الاتصال المحدد. إذا لم يتم تقديم أي رد اتصال، فسيتم فرز القائمة باستخدام وظيفة المقارنة الافتراضية.public function filter(callable $callback) : JsonList
: يقوم بتصفية القائمة باستخدام رد الاتصال المحدد. يجب أن يُرجع رد الاتصال قيمة منطقية. إذا أعاد رد الاتصال true
، فسيتم تضمين العنصر في القائمة الناتجة. إذا أعادت false
، فسيتم تجاهل العنصر.