PHP語言Fiber物件

吳修福 Hugh Wu

  • 精誠資訊/恆逸教育訓練中心-資深講師
  • 技術分類:程式設計

 

 

PHP自從發展到8.0之後,不管在性能及語言功能上都有大幅度的進步,因此在開發者中的使用比例也慢慢在增加中。

從8.0開始,PHP中新增了一個Fiber類別,它有自己的呼叫堆疊(call stack),開發人員可以在任何需要的時候利用它暫停函數的執行並回傳執行結果,也可以在恢復執行時傳遞參數進去,只是這跟一般的函數使用方式不一樣。

首先來看看如何建立Fiber物件,Fiber的建構子參數需要一個函數,可以使用匿名函數:

    $fiber = new Fiber(function(): void {
        ....
    }); 

利用Closure也可以:

    function ff(): void {
        ....
    }
    
    $ff = ff(...);
    $fiber = new Fiber($ff); 

建立起來之後就可以呼叫start()(實體方法)開始執行Fiber物件中的函數了。start() 及resume() 的回傳值即為suspend()(類別方法)的參數,恢復執行可以呼叫Fiber的實體方法resume(),此方法的參數值會成為之前suspend() 的回傳值:

    $fiber = new Fiber(function(): void {
        // 暫停時要回傳給caller的值放在 suspend 的參數
        $resume_value = Fiber::suspend('hello');
        echo "Value used to resume: ", $resume_value, PHP_EOL;
        echo "end of function.\n";
    });
    
    // 呼叫 start() 後開始執行函數,函數中 suspend() 時會回傳值
    $suspend_value = $fiber->start();
    echo "Value from fiber suspending: ", $suspend_value, PHP_EOL;
    $fiber->resume('world'); 

執行結果:

    Value from fiber suspending: hello
    Value used to resume: world
    end of function. 

除了以上的方法,還有其他方法也可以來跟Fiber進行互動:

類別方法:
getCurrent():取得目前Fiber物件。

實體方法:
throw(Throwable):恢復Fiber執行,並在Fiber中的暫停點引發一個指定的例外。
getReturn():取得Fiber中函數執行完成後的回傳值。
isStarted():判定Fiber是否已起動。
isSuspend():判定Fiber是否已暫停。
isRunning():判定Fiber是否正在執行中。
isTerminated():判定Fiber是否已執行結束。

以下是上述這些方法的範例程式:

    function func(): int {
        try {
            $value = Fiber::suspend('fiber');
        }
        catch (Exception $ex) {
            echo "exception caught: ", $ex, PHP_EOL;
        }
        echo "Value used to resume fiber: ", $value, PHP_EOL;
        echo "is running: ", Fiber::getCurrent()->isRunning(), PHP_EOL;
        return 200;
    }
    
    $fiber = new Fiber(func(...));
    echo "is started: ", $fiber->isStarted(), PHP_EOL;
    $value = $fiber->start();
    echo "is started: ", $fiber->isStarted(), PHP_EOL;
    echo "is running: ", $fiber->isRunning(), PHP_EOL;
    echo "is suspend: ", $fiber->isSuspended(), PHP_EOL;
    echo "Value from fiber suspending: ", $value, PHP_EOL;
    echo "is terminated: ", $fiber->isTerminated(), PHP_EOL;
    
    $fiber->resume('test');
    // 利用 throw() 恢復暫停的 Fiber
    //$fiber->throw(new Exception("my exception"));
    
    echo "is suspend: ", $fiber->isSuspended(), PHP_EOL;
    echo "is terminated: ", $fiber->isTerminated(), PHP_EOL;
    echo $fiber->getReturn(), PHP_EOL;

執行結果:

    is started: 
    is started: 1
    is running: 
    is suspend: 1
    Value from fiber suspending: fiber
    is terminated: 
    Value used to resume fiber: test
    is running: 1
    is suspend: 
    is terminated: 1
    200

經由以上這個例子,我們可以利用這些API跟Fiber物件進行更多互動來達到我們所需要的功能,像是做為Generator的替代方案,可以更有彈性的來處理更大量的資料喔!


您可在下列課程中了解更多技巧喔!