ไฟเบอร์ของ PHP 8.1
หยุดชั่วคราวและทำงานต่อด้วยไฟเบอร์แบบเนทีฟ
ไฟเบอร์ของ PHP 8.1 เป็นบทเรียน PHP Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน PHP Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส PHP Academy มีบทเรียนทั้งหมด 4 บทเรียน
สิ่งที่ไฟเบอร์มอบให้คุณ
PHP 8.1 เพิ่มไฟเบอร์: องค์ประกอบพื้นฐานระดับแกนหลักที่ช่วยให้คุณหยุดสแตกการเรียกที่กำลังทำงานอยู่ชั่วคราว แล้วกลับมาทำงานต่อภายหลังจากจุดที่แตกต่างไปโดยสิ้นเชิง ไฟเบอร์คือสแตกที่สมบูรณ์และเป็นอิสระ ซึ่งคุณสามารถหยุดไว้ที่จุดใดก็ได้ แล้วทำงานต่อโดยไม่ต้องคลายสแตก นี่คือส่วนที่ขาดหายไปซึ่งช่วยให้ไลบรารีเปลี่ยนสายพรอมิสให้เป็น await ที่ดูเหมือนทำงานแบบซิงโครนัสได้ — เป็นกลไกเบื้องหลัง API สมัยใหม่ของ ReactPHP และแอมป์
ไฟเบอร์แรกของคุณ
สร้างไฟเบอร์ด้วยฟังก์ชันเรียกกลับ เรียกใช้ start() แล้วปล่อยให้ไฟเบอร์หยุดชั่วคราวตัวเอง การควบคุมจะกลับไปยังผู้เรียก ณ จุดที่หยุดชั่วคราว และ resume() จะทำงานต่อจากจุดนั้นพอดี
<?php
$fiber = new Fiber(function (): void {
echo "A: inside fiber\n";
$received = Fiber::suspend('paused');
echo "C: resumed with '$received'\n";
});
$value = $fiber->start(); // prints A, returns 'paused'
echo "B: fiber suspended, got '$value'\n";
$fiber->resume('hello'); // prints C
echo "D: fiber done\n";เมธอดหลักสี่รายการ
ส่วนติดต่อโปรแกรมมีขนาดเล็ก:
$fiber->start(...$args)— เริ่มการทำงาน และส่งคืนค่าที่หยุดชั่วคราวครั้งแรกFiber::suspend($value)— หยุดไฟเบอร์ปัจจุบันชั่วคราว และส่ง$valueให้ผู้ที่ทำให้ทำงานต่อ$fiber->resume($value)— ทำงานต่อ โดย$valueจะกลายเป็นค่าที่suspend()ส่งคืน$fiber->getReturn()— ค่าที่ฟังก์ชันเรียกกลับส่งคืนหลังจากสิ้นสุดการทำงาน
ค่าจะไหลไปมาทั้งสองทิศทางผ่านขอบเขตการหยุดชั่วคราว
การส่งค่าทั้งสองทิศทาง
ไฟเบอร์สามารถส่งคำขอออกไปและรับการตอบกลับกลับเข้ามาได้ — นี่คือหัวใจของวิธีที่ลูปเหตุการณ์ป้อนผลลัพธ์อินพุต/เอาต์พุตเข้าไปในงานที่ถูกหยุดชั่วคราว
<?php
$fiber = new Fiber(function (): int {
$a = Fiber::suspend('need first number');
$b = Fiber::suspend('need second number');
return $a + $b;
});
$fiber->start(); // suspends: 'need first number'
$fiber->resume(10); // a = 10, suspends: 'need second number'
$fiber->resume(32); // b = 32, fiber returns
echo $fiber->getReturn(), PHP_EOL; // 42สถานะและการตรวจสอบไฟเบอร์
คุณสามารถสอบถามไฟเบอร์เกี่ยวกับวงจรชีวิตของมันได้ การเรียกใช้ resume() กับไฟเบอร์ที่สิ้นสุดแล้วจะส่งข้อผิดพลาด FiberError ดังนั้นควรใช้การตรวจสอบเหล่านี้เพื่อป้องกันเมื่อสร้างตัวจัดตารางงาน
<?php
$fiber = new Fiber(function () { Fiber::suspend(); });
var_dump($fiber->isStarted()); // false
$fiber->start();
var_dump($fiber->isStarted()); // true
var_dump($fiber->isSuspended()); // true
var_dump($fiber->isRunning()); // false (we're outside it)
$fiber->resume();
var_dump($fiber->isTerminated()); // trueการสร้างตัวจัดตารางงานขนาดเล็ก
ไฟเบอร์บวกกับคิวเท่ากับตัวจัดตารางงานแบบร่วมมือ แต่ละงานจะหยุดชั่วคราวเพื่อส่งต่อการควบคุม แล้วตัวจัดตารางงานจะวนให้แต่ละงานทำงานตามลำดับจนกว่างานทั้งหมดจะเสร็จ นี่คือโครงร่างภายในสภาพแวดล้อมการทำงานแบบอะซิงโครนัสทุกแห่ง
<?php
$tasks = [];
foreach (['X', 'Y', 'Z'] as $name) {
$tasks[] = new Fiber(function () use ($name) {
for ($i = 1; $i <= 2; $i++) {
echo "$name step $i\n";
Fiber::suspend(); // give others a turn
}
});
}
foreach ($tasks as $t) { $t->start(); }
while ($tasks) {
foreach ($tasks as $k => $t) {
if ($t->isTerminated()) { unset($tasks[$k]); continue; }
$t->resume();
}
}ข้อยกเว้นข้ามขอบเขต
throwInto() (ในส่วนติดต่อโปรแกรมเรียกว่า throw() ในรูปแบบ $fiber->throw()) จะแทรกข้อยกเว้นที่จุดหยุดชั่วคราว — เป็นวิธีที่ลูปรายงานการดำเนินการอินพุต/เอาต์พุตที่ล้มเหลวกลับไปยังงานที่กำลังรอผล ข้อยกเว้นจะปรากฏตรงจุดที่ไฟเบอร์หยุดไว้พอดี
<?php
$fiber = new Fiber(function () {
try {
Fiber::suspend();
} catch (RuntimeException $e) {
echo 'caught: ' . $e->getMessage() . PHP_EOL;
}
});
$fiber->start();
$fiber->throw(new RuntimeException('io failed')); // prints: caught: io failedไฟเบอร์เทียบกับเจเนอเรเตอร์
เจเนอเรเตอร์ (yield) ก็หยุดชั่วคราวได้เช่นกัน — แต่หยุดได้เฉพาะฟังก์ชันชั้นนอกสุดเท่านั้น หากต้องการรอผลจากตัวช่วยที่ซ้อนอยู่ภายในโดยใช้เจเนอเรเตอร์ คุณต้องใช้ yield from ไล่ขึ้นไปตลอดสแตก ทำให้ทุกฟังก์ชันต้องรองรับรูปแบบนี้ ไฟเบอร์หยุดทั้งสแตกได้จากทุกระดับ ดังนั้นการเรียกที่ซ้อนลึกจึงสามารถเรียกใช้ Fiber::suspend() ได้โดยที่ผู้เรียกไม่จำเป็นต้องทราบ นี่คือเหตุผลที่ await สามารถเป็นการเรียกฟังก์ชันทั่วไปแทนที่จะเป็น yield
<?php
function deep(): string {
// No yield needed in the call chain — suspends the whole fiber
return Fiber::suspend('awaiting from deep');
}
$f = new Fiber(fn() => print(deep() . PHP_EOL));
$f->start();
$f->resume('value injected at depth');ข้อจำกัดของการหยุดชั่วคราว
มีกฎสำคัญเพียงข้อเดียว: คุณสามารถเรียกใช้ Fiber::suspend() ได้จากภายในไฟเบอร์เท่านั้น การหยุดจากเธรดหลัก หรือการหยุดข้ามฟังก์ชันเรียกกลับระดับ C ที่ไม่รองรับไฟเบอร์ (เช่น ตัวเปรียบเทียบ usort รุ่นเก่าบางตัวและฟังก์ชันเรียกกลับภายในบางประเภท) จะส่งข้อผิดพลาด FiberError: Cannot suspend outside of a fiber ไลบรารีจะซ่อนข้อจำกัดนี้โดยทำให้แน่ใจว่าโค้ดของผู้ใช้ทั้งหมดทำงานภายในไฟเบอร์ที่ลูปเป็นผู้ขับเคลื่อน
<?php
try {
Fiber::suspend(); // main thread — illegal
} catch (FiberError $e) {
echo $e->getMessage(), PHP_EOL; // Cannot suspend outside of a fiber
}ไลบรารีใช้ไฟเบอร์อย่างไร
โดยทั่วไปคุณแทบไม่ต้องเขียนไฟเบอร์โดยตรงในโค้ดแอปพลิเคชัน เฟรมเวิร์กอย่างแอมป์ v3 และReactPHP (ผ่านไฟเบอร์)จะห่อหุ้มไฟเบอร์ไว้: await($promise) จะเรียกใช้ Fiber::suspend() ภายใน ลงทะเบียนการทำงานต่อกับลูปเหตุการณ์ และเรียก resume() ให้ไฟเบอร์ของคุณเมื่ออินพุต/เอาต์พุตเสร็จสมบูรณ์ โค้ดของคุณจึงดูเหมือนทำงานแบบซิงโครนัส ขณะที่สภาพแวดล้อมขณะทำงานจัดการการพักและการจัดตารางงานให้
<?php
// Conceptual: what an await() helper does under the hood
function await(Promise $p): mixed {
$fiber = Fiber::getCurrent() ?? throw new Error('await() outside fiber');
$p->then(fn($v) => $fiber->resume($v),
fn($e) => $fiber->throw($e));
return Fiber::suspend(); // parked until the promise settles
}ข้อควรระวังด้านหน่วยความจำและวงจรชีวิต
ไฟเบอร์แต่ละตัวจัดสรรสแตกของตัวเอง ดังนั้นการสร้างไฟเบอร์หลายแสนตัวจึงมีต้นทุนด้านหน่วยความจำ (แม้จะใช้ทรัพยากรน้อยกว่าเธรดของ OS มาก) ไฟเบอร์ที่ถูกหยุดไว้ตลอดไปจะไม่ถูกเก็บคืนโดยตัวเก็บขยะ หากยังมีบางสิ่งอ้างอิงถึงมันอยู่ — เป็นหน่วยความจำรั่วที่ตรวจพบได้ยากในเซิร์ฟเวอร์ที่ทำงานต่อเนื่อง นอกจากนี้ หากฟังก์ชันเรียกกลับของไฟเบอร์ส่งข้อยกเว้นที่ไม่ถูกดักจับ ข้อยกเว้นนั้นจะส่งต่อออกมาจากการเรียก resume()/start() ดังนั้นตัวจัดตารางงานต้องครอบการทำงานต่อด้วยบล็อกดักจับข้อผิดพลาด
<?php
$fiber = new Fiber(function () {
throw new RuntimeException('boom inside fiber');
});
try {
$fiber->start(); // exception surfaces here, at the resumer
} catch (RuntimeException $e) {
echo 'scheduler caught: ' . $e->getMessage() . PHP_EOL;
}ตรวจสอบความเข้าใจ
ไฟเบอร์มีข้อได้เปรียบสำคัญอะไรเหนือเจเนอเรเตอร์สำหรับการทำงานแบบอะซิงโครนัส
สรุปทบทวน
ไฟเบอร์คือองค์ประกอบพื้นฐานระดับต่ำสำหรับการทำงานพร้อมกันของ PHP:
start(),Fiber::suspend(),resume(),getReturn()สามารถหยุดและทำงานต่อทั้งสแตกการเรียก โดยส่งค่ากันทั้งสองทิศทาง- เมธอดสถานะ (
isSuspended,isTerminated) และthrow()ช่วยให้คุณสร้างตัวจัดตารางงานแบบร่วมมือและแทรกข้อผิดพลาดจากอินพุต/เอาต์พุตได้ - ต่างจากเจเนอเรเตอร์ ไฟเบอร์สามารถหยุดได้จากทุกระดับ — จึงเปิดใช้งาน
await()ที่โปร่งใส - คุณสามารถหยุดชั่วคราวได้เฉพาะภายในไฟเบอร์เท่านั้น เฟรมเวิร์กอย่างแอมป์และ ReactPHP จะห่อหุ้มไฟเบอร์ไว้ ทำให้โค้ดแบบอะซิงโครนัสของคุณอ่านได้เหมือนโค้ดแบบซิงโครนัส
เรียนรู้ PHP ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 49
- บทเรียน
- 195
คำถามที่พบบ่อย
บทเรียน “ไฟเบอร์ของ PHP 8.1” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ไฟเบอร์ของ PHP 8.1” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส PHP Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส PHP Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ไฟเบอร์ของ PHP 8.1”
หยุดชั่วคราวและทำงานต่อด้วยไฟเบอร์แบบเนทีฟ คุณปฏิบัติ PHP Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน PHP Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน PHP Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “ไฟเบอร์ของ PHP 8.1” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน PHP Academy นี้ได้ไหม
ได้ บทเรียน PHP Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- โมเดลการทำงานพร้อมกันของ PHP
- ไฟเบอร์ของ PHP 8.1
- ลูปเหตุการณ์ด้วย ReactPHP
- เซิร์ฟเวอร์ประสิทธิภาพสูงด้วย Swoole