jsonobject
jsonobject
เป็นคลาส PHP เพื่อลดความยุ่งยากในการใช้งานอ็อบเจ็กต์ที่มาจากคำจำกัดความ JSON แนวคิดนี้มาจากการใช้ pydantic
ใน python และความสามารถในการแยกวิเคราะห์และตรวจสอบความถูกต้องของข้อมูล json ลงในอ็อบเจ็กต์
jsonobject
ฉันต้องใช้ API จาก PHP และ API นั้นส่งคืน jsonobject ให้ฉัน ดังนั้นฉันจึงจำเป็นต้องแยกวิเคราะห์พวกมันเป็นออบเจ็กต์ 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 สำหรับตัวเลข ว่างสำหรับสตริง รายการ หรือ dicts) แอตทริบิวต์ birthDate ยังไม่บังคับและยังไม่ได้ตั้งค่า ดังนั้นจึงไม่ถูกสร้างขึ้นในเอาต์พุต
null
ในแอตทริบิวต์บังคับปัญหาของการตั้งค่าเป็น null มีความเกี่ยวข้องเป็นพิเศษเมื่อพิจารณาว่าแอตทริบิวต์เป็นทางเลือกหรือไม่
อาจมีคนคิดว่าหากเราตั้งค่าเป็น null นั่นหมายความว่าจะต้อง ยกเลิกการตั้ง ค่า ดังนั้นค่าดังกล่าวจึงควรเป็นไปได้สำหรับค่าเผื่อเลือกเท่านั้น ไม่ใช่ค่าบังคับ
ใน jsonobject
เรามีแนวคิดที่แตกต่างออกไป เนื่องจากการตั้งค่าคุณสมบัติเป็น โมฆะ จะหมายถึง "การตั้งค่าเป็น โมฆะ " และไม่ยกเลิกการตั้งค่าคุณสมบัติ ในการที่จะ ยกเลิกการตั้งค่า คุณสมบัติ เราควรใช้ฟังก์ชั่น unset หรืออะไรประมาณนั้น
jsonobject
ยังเปิดใช้งานเพื่อ ยกเลิกการตั้ง ค่า สำหรับแอตทริบิวต์ทางเลือก หมายถึง การลบค่าออก ดังนั้นจึงไม่มีค่าใดๆ ในการแสดงอาร์เรย์หรือออบเจ็กต์ (หากดึงค่า ค่าดังกล่าวจะถูกตั้งค่าเป็น null )
แต่สำหรับแอตทริบิวต์บังคับ การยกเลิกการตั้งค่าจะหมายถึง การรีเซ็ตค่าเป็นค่าเริ่มต้น นั่นหมายความว่าจะมีการกำหนดค่าเริ่มต้นเป็นค่าเริ่มต้นของประเภท (เช่น 0 สำหรับตัวเลข ว่างเปล่าสำหรับรายการ สตริงหรือคำสั่ง ฯลฯ) หรือค่าเริ่มต้นในค่าคงที่ ATTRIBUTES
jsonobject
ยังสามารถสืบทอดคุณลักษณะจากคลาสพาเรนต์ได้อีกด้วย ใช้ตัวอย่างต่อไปนี้:
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
จะมีเฉพาะแอตทริบิวต์ brand และ color แต่คลาส Car
จะมีแอตทริบิวต์ brand , color และ wheel ในขณะที่คลาส Boat
จะมีแอตทริบิวต์ brand , color และ length
สามารถสร้างออบเจ็กต์จากคลาสลูกของ 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"]) แต่ (ในขณะที่เขียนข้อความนี้) ประเภทขององค์ประกอบที่แทรกในพจนานุกรมจะไม่ได้รับการตรวจสอบ ประเภทนี้ใช้สำหรับการแยกวิเคราะห์เนื้อหาเมื่อสร้าง dict (เช่น การใช้ฟังก์ชันคง fromArray
) หรือเพื่อถ่ายโอนเนื้อหาไปยังอาร์เรย์หรืออ็อบเจ็กต์ (เช่น การใช้ฟังก์ชัน toArray
)
วิธีการคือ:
toArray()
toObject()
::fromArray($data)
::fromObject($data)
วิธีการเหล่านี้ถูกตีความในลักษณะเดียวกับในกรณีของ jsonobject
และประเภทขององค์ประกอบใน dict อาจหมายถึงประเภทที่ซับซ้อนซึ่งจะได้รับการพิจารณาแบบวนซ้ำเมื่อแยกวิเคราะห์เนื้อหา
เช่นประเภท 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
วิธีที่จะทำให้มันคือการกำหนด tuple [ <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
คุณลักษณะที่สำคัญคือ ถ้าสตริงที่ตั้งค่าเป็น <default value> สอดคล้องกับเมธอดของอ็อบเจ็กต์ มันจะถูกเรียกเมื่อได้รับค่า (หากยังไม่ได้ตั้งค่า) และค่าที่ตั้งไว้สำหรับคุณสมบัตินั้นจะ เป็นผลมาจากการโทร
เช่น
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
-type
เช่น
$ 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
องค์ประกอบจะถูกละทิ้ง