ใช้งานง่ายมากและแทนที่หน่วยความจำได้อย่างมีประสิทธิภาพ สำหรับการวนซ้ำไฟล์ JSON ขนาดใหญ่หรือสตรีมที่ไม่มีประสิทธิภาพสำหรับ PHP >=7.2 ดู TL; DR ไม่มีการพึ่งพาในการผลิตยกเว้น ext-json
ทางเลือก README ซิงค์กับโค้ด
ใหม่ในเวอร์ชัน 1.2.0
- การวนซ้ำแบบเรียกซ้ำ
<?php
use JsonMachineItems;
// this often causes Allowed Memory Size Exhausted,
// because it loads all the items in the JSON into memory
- $users = json_decode(file_get_contents('500MB-users.json'));
// this has very small memory footprint no matter the file size
// because it loads items into memory one by one
+ $users = Items::fromFile('500MB-users.json');
foreach ($users as $id => $user) {
// just process $user as usual
var_dump($user->name);
}
การเข้าถึงแบบสุ่มเช่น $users[42]
ยังไม่สามารถทำได้ ใช้ foreach
ที่กล่าวมาข้างต้นและค้นหารายการหรือใช้ JSON Pointer
นับรายการผ่าน iterator_count($users)
โปรดจำไว้ว่ายังคงต้องวนซ้ำทั้งหมดภายในเพื่อนับจำนวน และจะใช้เวลาประมาณเดียวกับการวนซ้ำและนับด้วยมือ
ต้องใช้ ext-json
หากใช้นอกกรอบ แต่ไม่ต้องใช้หากใช้ตัวถอดรหัสแบบกำหนดเอง ดูตัวถอดรหัส
ติดตาม CHANGELOG
JSON Machine เป็นตัวแยกวิเคราะห์ JSON สตรีม/ดึง/ส่วนเพิ่ม/ขี้เกียจ (ไม่ว่าคุณจะตั้งชื่ออะไรก็ตาม) ที่มีประสิทธิภาพ ใช้งานง่าย และรวดเร็ว โดยอิงจากตัวสร้างที่พัฒนาขึ้นสำหรับสตรีมหรือเอกสาร JSON ที่ยาวอย่างไม่อาจคาดเดาได้ คุณสมบัติหลักคือ:
foreach
ไม่มีกิจกรรมและการโทรกลับjson_decode
ดั้งเดิมเพื่อถอดรหัสรายการเอกสาร JSON ตามค่าเริ่มต้น ดูตัวถอดรหัส สมมติว่า fruits.json
มีเอกสาร JSON ขนาดใหญ่นี้:
// fruits.json
{
"apple" : {
"color" : " red "
},
"pear" : {
"color" : " yellow "
}
}
สามารถแยกวิเคราะห์ได้ดังนี้:
<?php
use JsonMachine Items ;
$ fruits = Items:: fromFile ( ' fruits.json ' );
foreach ( $ fruits as $ name => $ data ) {
// 1st iteration: $name === "apple" and $data->color === "red"
// 2nd iteration: $name === "pear" and $data->color === "yellow"
}
การแยกวิเคราะห์อาร์เรย์ json แทนวัตถุ json เป็นไปตามตรรกะเดียวกัน คีย์ใน foreach จะเป็นดัชนีตัวเลขของรายการ
หากคุณต้องการให้เครื่อง JSON ส่งคืนอาร์เรย์แทนอ็อบเจ็กต์ ให้ใช้ new ExtJsonDecoder(true)
เป็นตัวถอดรหัส
<?php
use JsonMachine JsonDecoder ExtJsonDecoder ;
use JsonMachine Items ;
$ objects = Items:: fromFile ( ' path/to.json ' , [ ' decoder ' => new ExtJsonDecoder ( true )]);
หากคุณต้องการวนซ้ำเฉพาะทรีย่อย results
ใน fruits.json
นี้ :
// fruits.json
{
"results" : {
"apple" : {
"color" : " red "
},
"pear" : {
"color" : " yellow "
}
}
}
ใช้ JSON Pointer /results
เป็นตัวเลือก pointer
:
<?php
use JsonMachine Items ;
$ fruits = Items:: fromFile ( ' fruits.json ' , [ ' pointer ' => ' /results ' ]);
foreach ( $ fruits as $ name => $ data ) {
// The same as above, which means:
// 1st iteration: $name === "apple" and $data->color === "red"
// 2nd iteration: $name === "pear" and $data->color === "yellow"
}
บันทึก:
ค่าของ
results
ไม่ได้ถูกโหลดลงในหน่วยความจำในครั้งเดียว แต่จะมีเพียงรายการเดียวเท่านั้นในresults
ในแต่ละครั้ง โดยจะเป็นหนึ่งรายการในหน่วยความจำในแต่ละครั้งในระดับ/แผนผังย่อยที่คุณกำลังวนซ้ำอยู่ ดังนั้นการใช้หน่วยความจำจึงคงที่
ข้อมูลจำเพาะของ JSON Pointer ยังอนุญาตให้ใช้ยัติภังค์ ( -
) แทนดัชนีอาร์เรย์เฉพาะ เครื่อง JSON ตีความว่าเป็นไวด์การ์ดซึ่งตรงกับ ดัชนีอาร์เรย์ ใดๆ (ไม่ใช่คีย์ออบเจ็กต์ใดๆ) ซึ่งช่วยให้คุณสามารถวนซ้ำค่าที่ซ้อนกันในอาร์เรย์โดยไม่ต้องโหลดรายการทั้งหมด
ตัวอย่าง:
// fruitsArray.json
{
"results" : [
{
"name" : " apple " ,
"color" : " red "
},
{
"name" : " pear " ,
"color" : " yellow "
}
]
}
หากต้องการวนซ้ำผลไม้ทุกสี ให้ใช้ JSON Pointer "/results/-/color"
<?php
use JsonMachine Items ;
$ fruits = Items:: fromFile ( ' fruitsArray.json ' , [ ' pointer ' => ' /results/-/color ' ]);
foreach ( $ fruits as $ key => $ value ) {
// 1st iteration:
$ key == ' color ' ;
$ value == ' red ' ;
$ fruits -> getMatchedJsonPointer () == ' /results/-/color ' ;
$ fruits -> getCurrentJsonPointer () == ' /results/0/color ' ;
// 2nd iteration:
$ key == ' color ' ;
$ value == ' yellow ' ;
$ fruits -> getMatchedJsonPointer () == ' /results/-/color ' ;
$ fruits -> getCurrentJsonPointer () == ' /results/1/color ' ;
}
คุณสามารถแยกวิเคราะห์ค่าสเกลาร์ค่าเดียวที่ใดก็ได้ในเอกสารในลักษณะเดียวกับคอลเลกชัน ลองพิจารณาตัวอย่างนี้:
// fruits.json
{
"lastModified" : " 2012-12-12 " ,
"apple" : {
"color" : " red "
},
"pear" : {
"color" : " yellow "
},
// ... gigabytes follow ...
}
รับค่าสเกลาร์ของคีย์ lastModified
ดังนี้:
<?php
use JsonMachine Items ;
$ fruits = Items:: fromFile ( ' fruits.json ' , [ ' pointer ' => ' /lastModified ' ]);
foreach ( $ fruits as $ key => $ value ) {
// 1st and final iteration:
// $key === 'lastModified'
// $value === '2012-12-12'
}
เมื่อ parser ค้นหาค่าและมอบค่าให้กับคุณ Parser จะหยุดการแยกวิเคราะห์ ดังนั้นเมื่อค่าสเกลาร์ค่าเดียวอยู่ที่จุดเริ่มต้นของไฟล์หรือสตรีมขนาดกิกะไบต์ ค่านั้นจะได้รับค่าจากจุดเริ่มต้นในเวลาไม่นานและแทบไม่มีการใช้หน่วยความจำเลย
ทางลัดที่ชัดเจนคือ:
<?php
use JsonMachine Items ;
$ fruits = Items:: fromFile ( ' fruits.json ' , [ ' pointer ' => ' /lastModified ' ]);
$ lastModified = iterator_to_array ( $ fruits )[ ' lastModified ' ];
การเข้าถึงค่าสเกลาร์เดี่ยวรองรับดัชนีอาร์เรย์ในตัวชี้ JSON เช่นกัน
นอกจากนี้ยังสามารถแยกวิเคราะห์แผนผังย่อยหลายรายการโดยใช้ตัวชี้ JSON หลายตัวได้ ลองพิจารณาตัวอย่างนี้:
// fruits.json
{
"lastModified" : " 2012-12-12 " ,
"berries" : [
{
"name" : " strawberry " , // not a berry, but whatever ...
"color" : " red "
},
{
"name" : " raspberry " , // the same ...
"color" : " red "
}
],
"citruses" : [
{
"name" : " orange " ,
"color" : " orange "
},
{
"name" : " lime " ,
"color" : " green "
}
]
}
หากต้องการวนซ้ำผลเบอร์รี่และผลไม้รสเปรี้ยวทั้งหมด ให้ใช้ตัวชี้ JSON ["/berries", "/citrus"]
ลำดับของพอยน์เตอร์ไม่สำคัญ รายการจะถูกวนซ้ำตามลำดับที่ปรากฏในเอกสาร
<?php
use JsonMachine Items ;
$ fruits = Items:: fromFile ( ' fruits.json ' , [
' pointer ' => [ ' /berries ' , ' /citruses ' ]
]);
foreach ( $ fruits as $ key => $ value ) {
// 1st iteration:
$ value == [ " name " => " strawberry " , " color " => " red " ];
$ fruits -> getCurrentJsonPointer () == ' /berries ' ;
// 2nd iteration:
$ value == [ " name " => " raspberry " , " color " => " red " ];
$ fruits -> getCurrentJsonPointer () == ' /berries ' ;
// 3rd iteration:
$ value == [ " name " => " orange " , " color " => " orange " ];
$ fruits -> getCurrentJsonPointer () == ' /citruses ' ;
// 4th iteration:
$ value == [ " name " => " lime " , " color " => " green " ];
$ fruits -> getCurrentJsonPointer () == ' /citruses ' ;
}
ใช้ RecursiveItems
แทน Items
เมื่อโครงสร้าง JSON ยากหรือเป็นไปไม่ได้เลยที่จะจัดการกับ Items
และตัวชี้ JSON หรือแต่ละรายการที่คุณวนซ้ำนั้นใหญ่เกินกว่าจะจัดการได้ ในทางกลับกัน มันช้ากว่า Items
อย่างเห็นได้ชัด ดังนั้นโปรดจำไว้เสมอ
เมื่อ RecursiveItems
พบรายการหรือคำสั่งใน JSON มันจะส่งคืนอินสแตนซ์ใหม่ของตัวเองซึ่งสามารถทำซ้ำได้และวนซ้ำ ดังนั้น มันจะไม่ส่งคืนอาร์เรย์หรืออ็อบเจ็กต์ PHP แต่จะส่งคืนเฉพาะค่าสเกลาร์หรือ RecursiveItems
เท่านั้น จะไม่มีการโหลด JSON dict หรือรายการลงในหน่วยความจำอย่างสมบูรณ์ในครั้งเดียว
มาดูตัวอย่างกับผู้ใช้หลายคนกับเพื่อนมากมาย:
// users.json
[
{
"username" : " user " ,
"e-mail" : " [email protected] " ,
"friends" : [
{
"username" : " friend1 " ,
"e-mail" : " [email protected] "
},
{
"username" : " friend2 " ,
"e-mail" : " [email protected] "
}
]
}
]
<?php
use JsonMachine RecursiveItems
$ users = RecursiveItems:: fromFile ( ' users.json ' );
foreach ( $ users as $ user ) {
/** @var $user RecursiveItems */
foreach ( $ user as $ field => $ value ) {
if ( $ field === ' friends ' ) {
/** @var $value RecursiveItems */
foreach ( $ value as $ friend ) {
/** @var $friend RecursiveItems */
foreach ( $ friend as $ friendField => $ friendValue ) {
$ friendField == ' username ' ;
$ friendValue == ' friend1 ' ;
}
}
}
}
}
หากคุณหยุดการวนซ้ำของระดับที่ลึกกว่านั้น (เช่น คุณข้าม
"friends"
บางส่วนด้วยbreak
) และเลื่อนไปยังค่าถัดไป (เช่นuser
รายถัดไป ) คุณจะไม่สามารถทำซ้ำได้ในภายหลัง เครื่อง JSON ต้องวนซ้ำในเบื้องหลังเพื่อให้สามารถอ่านค่าถัดไปได้ ความพยายามดังกล่าวจะส่งผลให้เกิดข้อยกเว้นของตัวสร้างที่ปิด
RecursiveItems
toArray(): array
หากคุณแน่ใจว่า RecursiveItems บางตัวชี้ไปที่โครงสร้างข้อมูลที่สามารถจัดการหน่วยความจำได้ (เช่น $friend) คุณสามารถเรียก $friend->toArray()
และรายการนั้นจะกลายเป็น อาร์เรย์ PHP ธรรมดา
advanceToKey(int|string $key): scalar|RecursiveItems
เมื่อค้นหาคีย์เฉพาะในคอลเลกชัน (เช่น 'friends'
ใน $user
) คุณไม่จำเป็นต้องใช้การวนซ้ำและเงื่อนไขในการค้นหา คุณสามารถเรียก $user->advanceToKey("friends")
แทนได้ มันจะวนซ้ำสำหรับคุณและส่งกลับค่าที่คีย์นี้ การโทรสามารถถูกล่ามโซ่ได้ นอกจากนี้ยังรองรับ อาร์เรย์เช่นไวยากรณ์ เพื่อก้าวไปสู่และรับดัชนีต่อไปนี้ ดังนั้น $user['friends']
จะเป็นนามแฝงสำหรับ $user->advanceToKey('friends')
การโทรสามารถถูกล่ามโซ่ได้ โปรดทราบว่านี่เป็นเพียงนามแฝง คุณจะไม่สามารถเข้าถึงดัชนีก่อนหน้าโดยสุ่มได้ หลังจากใช้สิ่งนี้กับ RecursiveItems
โดยตรง มันเป็นเพียงน้ำตาลไวยากรณ์ ใช้ toArray()
หากคุณต้องการเข้าถึงดัชนีในบันทึก/รายการแบบสุ่ม
ตัวอย่างก่อนหน้านี้อาจถูกทำให้ง่ายขึ้นดังนี้:
<?php
use JsonMachine RecursiveItems
$ users = RecursiveItems:: fromFile ( ' users.json ' );
foreach ( $ users as $ user ) {
/** @var $user RecursiveItems */
foreach ( $ user [ ' friends ' ] as $ friend ) { // or $user->advanceToKey('friends')
/** @var $friend RecursiveItems */
$ friendArray = $ friend -> toArray ();
$ friendArray [ ' username ' ] === ' friend1 ' ;
}
}
การผูกมัดช่วยให้คุณทำสิ่งนี้:
<?php
use JsonMachine RecursiveItems
$ users = RecursiveItems:: fromFile ( ' users.json ' );
$ users [ 0 ][ ' friends ' ][ 1 ][ ' username ' ] === ' friend2 ' ;
RecursiveItems implements RecursiveIterator
ดังนั้นคุณสามารถใช้ตัวอย่างเครื่องมือในตัวของ PHP เพื่อทำงานกับ RecursiveIterator
เช่น:
เป็นวิธีการจัดการหนึ่งรายการในเอกสาร JSON ดู JSON Pointer RFC 6901 ซึ่งมีประโยชน์มาก เพราะบางครั้งโครงสร้าง JSON เจาะลึกลงไปอีก และคุณต้องการวนซ้ำแผนผังย่อย ไม่ใช่ระดับหลัก ดังนั้นคุณเพียงแค่ระบุตัวชี้ไปยังอาร์เรย์ JSON หรือวัตถุ (หรือแม้แต่ค่าสเกลาร์) ที่คุณต้องการวนซ้ำและดำเนินการต่อไป เมื่อ parser เข้าถึงคอลเล็กชันที่คุณระบุ การวนซ้ำจะเริ่มต้นขึ้น คุณสามารถส่งผ่านเป็นตัวเลือก pointer
ในทุกฟังก์ชัน Items::from*
หากคุณระบุตัวชี้ไปยังตำแหน่งที่ไม่มีอยู่ในเอกสาร ข้อยกเว้นจะเกิดขึ้น สามารถใช้เพื่อเข้าถึงค่าสเกลาร์ได้เช่นกัน ตัวชี้ JSON จะต้องเป็นสตริง JSON ที่ถูกต้อง การเปรียบเทียบโทเค็นอ้างอิงตามตัวอักษร (ส่วนระหว่างเครื่องหมายทับ) จะดำเนินการกับคีย์เอกสาร JSON/ชื่อสมาชิก
ตัวอย่างบางส่วน:
ค่าตัวชี้ JSON | จะวนซ้ำผ่าน. |
---|---|
(สตริงว่าง - ค่าเริ่มต้น) | ["this", "array"] หรือ {"a": "this", "b": "object"} จะถูกวนซ้ำ (ระดับหลัก) |
/result/items | {"result": {"items": ["this", "array", "will", "be", "iterated"]}} |
/0/items | [{"items": ["this", "array", "will", "be", "iterated"]}] (รองรับดัชนีอาร์เรย์) |
/results/-/status | {"results": [{"status": "iterated"}, {"status": "also iterated"}]} (ยัติภังค์เป็นสัญลักษณ์ตัวแทนดัชนีอาร์เรย์) |
/ (gotcha! - เครื่องหมายทับตามด้วยสตริงว่าง โปรดดูข้อมูลจำเพาะ) | {"":["this","array","will","be","iterated"]} |
/quotes" | {"quotes"": ["this", "array", "will", "be", "iterated"]} |
ตัวเลือกอาจเปลี่ยนวิธีแยกวิเคราะห์ JSON อาร์เรย์ของตัวเลือกคือพารามิเตอร์ตัวที่สองของฟังก์ชัน Items::from*
ทั้งหมด ตัวเลือกที่ใช้ได้คือ:
pointer
- สตริง JSON Pointer ที่บอกว่าส่วนใดของเอกสารที่คุณต้องการทำซ้ำdecoder
- อินสแตนซ์ของอินเทอร์เฟซ ItemDecoder
debug
- true
หรือ false
เพื่อเปิดหรือปิดโหมดแก้ไขข้อบกพร่อง เมื่อเปิดใช้งานโหมดแก้ไขข้อบกพร่อง ข้อมูล เช่น บรรทัด คอลัมน์ และตำแหน่งในเอกสารจะพร้อมใช้งานในระหว่างการแยกวิเคราะห์หรือในข้อยกเว้น การปิดใช้งานการแก้ไขข้อบกพร่องจะเพิ่มความได้เปรียบด้านประสิทธิภาพเล็กน้อย การตอบสนองของสตรีม API หรือสตรีม JSON อื่นๆ จะถูกแยกวิเคราะห์ในลักษณะเดียวกับไฟล์ทุกประการ ข้อแตกต่างเพียงอย่างเดียวคือ คุณใช้ Items::fromStream($streamResource)
โดยที่ $streamResource
เป็นทรัพยากรสตรีมที่มีเอกสาร JSON ส่วนที่เหลือจะเหมือนกับการแยกวิเคราะห์ไฟล์ ต่อไปนี้คือตัวอย่างบางส่วนของไคลเอนต์ http ยอดนิยมที่รองรับการตอบสนองแบบสตรีมมิ่ง:
Guzzle ใช้สตรีมของตัวเอง แต่สามารถแปลงกลับเป็นสตรีม PHP ได้โดยการเรียก GuzzleHttpPsr7StreamWrapper::getResource()
ส่งผลลัพธ์ของฟังก์ชันนี้ไปยังฟังก์ชัน Items::fromStream
และคุณก็พร้อมแล้ว ดูตัวอย่างการทำงานของ GuzzleHttp
การตอบสนองสตรีมของ Symfony HttpClient ทำงานเป็นตัววนซ้ำ และเนื่องจาก JSON Machine ใช้ตัววนซ้ำ การผสานรวมกับ Symfony HttpClient จึงง่ายมาก ดูตัวอย่าง HttpClient
debug
) เอกสารขนาดใหญ่อาจใช้เวลาสักครู่ในการแยกวิเคราะห์ เรียก Items::getPosition()
ใน foreach
ของคุณเพื่อรับจำนวนไบต์ที่ประมวลผลในปัจจุบันตั้งแต่ต้น เปอร์เซ็นต์นั้นง่ายต่อการคำนวณเป็น position / total * 100
หากต้องการทราบขนาดรวมของเอกสารเป็นไบต์ คุณอาจต้องตรวจสอบ:
strlen($document)
หากคุณแยกวิเคราะห์สตริงfilesize($file)
หากคุณแยกวิเคราะห์ไฟล์Content-Length
หากคุณแยกวิเคราะห์การตอบสนองสตรีม http หากปิดใช้งาน debug
getPosition()
จะส่งคืนค่า 0
เสมอ
<?php
use JsonMachine Items ;
$ fileSize = filesize ( ' fruits.json ' );
$ fruits = Items:: fromFile ( ' fruits.json ' , [ ' debug ' => true ]);
foreach ( $ fruits as $ name => $ data ) {
echo ' Progress: ' . intval ( $ fruits -> getPosition () / $ fileSize * 100 ) . ' % ' ;
}
ฟังก์ชั่น Items::from*
ยังยอมรับตัวเลือก decoder
ด้วย ต้องเป็นอินสแตนซ์ของ JsonMachineJsonDecoderItemDecoder
หากไม่มีการระบุ ExtJsonDecoder
จะถูกใช้เป็นค่าเริ่มต้น จำเป็นต้องมีส่วนขยาย ext-json
PHP เนื่องจากใช้ json_decode
เมื่อ json_decode
ไม่ทำสิ่งที่คุณต้องการ ให้ใช้ JsonMachineJsonDecoderItemDecoder
และสร้างขึ้นมาเอง
ExtJsonDecoder
- ค่าเริ่มต้น ใช้ json_decode
เพื่อถอดรหัสคีย์และค่า Constructor มีพารามิเตอร์เหมือนกับ json_decode
PassThruDecoder
- ไม่มีการถอดรหัส ทั้งคีย์และค่าถูกสร้างขึ้นเป็นสตริง JSON ล้วนๆ มีประโยชน์เมื่อคุณต้องการแยกวิเคราะห์รายการ JSON ด้วยสิ่งอื่นโดยตรงใน foreach และไม่ต้องการใช้ JsonMachineJsonDecoderItemDecoder
เนื่องจาก 1.0.0
ไม่ได้ใช้ json_decode
ตัวอย่าง:
<?php
use JsonMachine JsonDecoder PassThruDecoder ;
use JsonMachine Items ;
$ items = Items:: fromFile ( ' path/to.json ' , [ ' decoder ' => new PassThruDecoder ]);
ErrorWrappingDecoder
- มัณฑนากรที่ห่อหุ้มข้อผิดพลาดในการถอดรหัสภายในวัตถุ DecodingError
ซึ่งทำให้คุณสามารถข้ามรายการที่ผิดรูปแบบแทนที่จะตายในข้อยกเว้น SyntaxError
ตัวอย่าง: <?php
use JsonMachine Items ;
use JsonMachine JsonDecoder DecodingError ;
use JsonMachine JsonDecoder ErrorWrappingDecoder ;
use JsonMachine JsonDecoder ExtJsonDecoder ;
$ items = Items:: fromFile ( ' path/to.json ' , [ ' decoder ' => new ErrorWrappingDecoder ( new ExtJsonDecoder ())]);
foreach ( $ items as $ key => $ item ) {
if ( $ key instanceof DecodingError || $ item instanceof DecodingError) {
// handle error of this malformed json item
continue ;
}
var_dump ( $ key , $ item );
}
ตั้งแต่ 0.4.0 ทุกข้อยกเว้นจะขยาย JsonMachineException
ดังนั้นคุณจึงสามารถจับได้ว่ากรองข้อผิดพลาดใด ๆ จากไลบรารี JSON Machine
หากมีข้อผิดพลาดที่ใดก็ได้ในสตรีม json ข้อยกเว้น SyntaxError
จะถูกส่งออกไป ซึ่งไม่สะดวกนัก เพราะหากมีข้อผิดพลาดภายในรายการ json รายการหนึ่ง คุณจะไม่สามารถแยกวิเคราะห์ส่วนที่เหลือของเอกสารได้เนื่องจากมีรายการหนึ่งที่มีรูปแบบไม่ถูกต้อง ErrorWrappingDecoder
เป็นตัวตกแต่งตัวถอดรหัสซึ่งสามารถช่วยคุณได้ ใส่ตัวถอดรหัสเข้าไปด้วย และรายการที่ผิดรูปแบบทั้งหมดที่คุณกำลังทำซ้ำจะถูกมอบให้กับคุณใน foreach ผ่านทาง DecodingError
วิธีนี้ทำให้คุณสามารถข้ามและดำเนินการต่อกับเอกสารได้ ดูตัวอย่างในตัวถอดรหัสที่มีอยู่ ข้อผิดพลาดทางไวยากรณ์ในโครงสร้างของสตรีม json ระหว่างรายการที่วนซ้ำจะยังคงส่งข้อยกเว้น SyntaxError
ความซับซ้อนของเวลาจะเป็น O(n)
เสมอ
TL; DR: ความซับซ้อนของหน่วยความจำคือ O(2)
เครื่อง JSON อ่านสตรีม (หรือไฟล์) รายการ JSON ครั้งละ 1 รายการ และสร้างรายการ PHP ที่เกี่ยวข้องครั้งละ 1 รายการ นี่เป็นวิธีที่มีประสิทธิภาพมากที่สุด เพราะหากคุณบอกว่ามีผู้ใช้ 10,000 รายในไฟล์ JSON และต้องการแยกวิเคราะห์โดยใช้ json_decode(file_get_contents('big.json'))
คุณจะมีสตริงทั้งหมดอยู่ในหน่วยความจำเช่นเดียวกับ 10,000 ทั้งหมด โครงสร้าง PHP ตารางต่อไปนี้แสดงความแตกต่าง:
สตริงรายการในหน่วยความจำในแต่ละครั้ง | ถอดรหัสรายการ PHP ในหน่วยความจำในแต่ละครั้ง | ทั้งหมด | |
---|---|---|---|
json_decode() | 10,000 | 10,000 | 20,000 |
Items::from*() | 1 | 1 | 2 |
ซึ่งหมายความว่า JSON Machine นั้นมีประสิทธิภาพอย่างต่อเนื่องสำหรับ JSON ที่ประมวลผลทุกขนาด 100GB ไม่มีปัญหา
TL; DR: ความซับซ้อนของหน่วยความจำคือ O(n+1)
นอกจากนี้ยังมีวิธี Items::fromString()
หากคุณถูกบังคับให้แยกวิเคราะห์สตริงขนาดใหญ่ และสตรีมไม่พร้อมใช้งาน JSON Machine อาจดีกว่า json_decode
เหตุผลก็คือ JSON Machine ยังคงสำรวจสตริง JSON ทีละรายการซึ่งแตกต่างจาก json_decode
และไม่โหลดโครงสร้าง PHP ที่เป็นผลลัพธ์ทั้งหมดลงในหน่วยความจำในครั้งเดียว
เรามาต่อด้วยตัวอย่างกับผู้ใช้ 10,000 ราย คราวนี้พวกเขาทั้งหมดอยู่ในสตริงในหน่วยความจำ เมื่อถอดรหัสสตริงนั้นด้วย json_decode
จะมีการสร้างอาร์เรย์ (อ็อบเจ็กต์) 10,000 รายการในหน่วยความจำ จากนั้นผลลัพธ์จะถูกส่งกลับ ในทางกลับกัน เครื่อง JSON จะสร้างโครงสร้างเดี่ยวสำหรับแต่ละรายการที่พบในสตริงและส่งกลับมาให้คุณ เมื่อคุณประมวลผลรายการนี้และวนซ้ำไปยังรายการถัดไป โครงสร้างเดียวอีกโครงสร้างหนึ่งจะถูกสร้างขึ้น นี่เป็นพฤติกรรมเดียวกันกับสตรีม/ไฟล์ ตารางต่อไปนี้ทำให้แนวคิดเป็นมุมมอง:
สตริงรายการในหน่วยความจำในแต่ละครั้ง | ถอดรหัสรายการ PHP ในหน่วยความจำในแต่ละครั้ง | ทั้งหมด | |
---|---|---|---|
json_decode() | 10,000 | 10,000 | 20,000 |
Items::fromString() | 10,000 | 1 | 10001 |
ความเป็นจริงยังดีกว่า Items::fromString
ใช้หน่วยความจำน้อยกว่า json_decode
ประมาณ 5 เท่า เหตุผลก็คือโครงสร้าง PHP ใช้หน่วยความจำมากกว่าการแสดง JSON ที่เกี่ยวข้อง
สาเหตุหนึ่งอาจเป็นเพราะรายการที่คุณต้องการวนซ้ำอยู่ในคีย์ย่อยบางคีย์ เช่น "results"
แต่คุณลืมระบุตัวชี้ JSON ดูการแยกวิเคราะห์แผนผังย่อย
อีกเหตุผลหนึ่งอาจเป็นได้ว่าหนึ่งในรายการที่คุณทำซ้ำนั้นมีขนาดใหญ่มากจนไม่สามารถถอดรหัสได้ในคราวเดียว ตัวอย่างเช่น คุณวนซ้ำผู้ใช้ และหนึ่งในนั้นมีออบเจ็กต์ "เพื่อน" นับพันรายการอยู่ในนั้น วิธีแก้ปัญหาที่มีประสิทธิภาพที่สุดคือการใช้การวนซ้ำ
อาจหมายความว่าสตริงสเกลาร์ JSON เดี่ยวนั้นใหญ่เกินกว่าจะใส่ในหน่วยความจำได้ ตัวอย่างเช่น ไฟล์ที่เข้ารหัส base64 ขนาดใหญ่มาก ในกรณีนั้น คุณอาจจะยังโชคไม่ดีจนกว่า JSON Machine จะรองรับการให้ค่าสเกลาร์เป็นสตรีม PHP
composer require halaxa/json-machine
โคลนหรือดาวน์โหลดที่เก็บนี้และเพิ่มสิ่งต่อไปนี้ลงในไฟล์บูตสแตรปของคุณ:
spl_autoload_register ( require ' /path/to/json-machine/src/autoloader.php ' );
โคลนที่เก็บนี้ ไลบรารีนี้สนับสนุนแนวทางการพัฒนาสองวิธี:
เรียกใช้ composer run -l
ในโปรเจ็กต์ dir เพื่อดูสคริปต์ dev ที่พร้อมใช้งาน วิธีนี้ทำให้คุณสามารถรันบางขั้นตอนของกระบวนการสร้าง เช่น การทดสอบ
ติดตั้ง Docker และรัน make
ใน project dir บนเครื่องโฮสต์ของคุณเพื่อดูเครื่องมือ/คำสั่ง dev ที่พร้อมใช้งาน คุณสามารถรันขั้นตอนทั้งหมดของกระบวนการสร้างแยกกัน รวมถึงกระบวนการสร้างทั้งหมดได้ในคราวเดียว โดยทั่วไปแล้ว Make จะรันสคริปต์ dev ของผู้แต่งภายในคอนเทนเนอร์ในเบื้องหลัง
make build
: รัน build ที่สมบูรณ์ คำสั่งเดียวกันนี้รันผ่าน GitHub Actions CI
คุณชอบห้องสมุดนี้หรือไม่? ติดดาว แบ่งปัน แสดง :) ยินดีอย่างยิ่งกับปัญหาและคำขอดึงข้อมูล
อาปาเช่ 2.0
องค์ประกอบล้อเฟือง: ไอคอนที่สร้างโดย TutsPlus จาก www.flaticon.com ได้รับอนุญาตจาก CC 3.0 BY
สารบัญที่สร้างด้วย markdown-toc