PHP Academy · บทเรียน

ไฟเบอร์ของ PHP 8.1

หยุดชั่วคราวและทำงานต่อด้วยไฟเบอร์แบบเนทีฟ

บทเรียน 2 จาก 413 ขั้นตอน

ไฟเบอร์ของ 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. โมเดลการทำงานพร้อมกันของ PHP
  2. ไฟเบอร์ของ PHP 8.1
  3. ลูปเหตุการณ์ด้วย ReactPHP
  4. เซิร์ฟเวอร์ประสิทธิภาพสูงด้วย Swoole
← กลับไปที่ PHP Academy