本文是我在研究 PHP 異步編程時的總結。對於至關多的 PHPer 來講,可能都不知道 Generator,或者對 Generaotr 的流程不是很熟悉。由於 Generator 使得程序再也不是順序的。鑑於本人的水平有限,若是有不一樣意見,還望指點一二,不勝感激!php
從 PHP 5 開始,PHP 爲咱們提供了 try catch 來進行異常處理。當咱們使用 catch 將異常捕獲,那麼一場後續的代碼就會執行。咱們看看下面的例子。編程
try { throw new Exception('e'); } catch (Exception $e) { echo $e->getMessage(); // output: e } echo 2; // output: 2
若是咱們沒有將異常捕獲,那麼後面的代碼就不會執行了。異步
throw new Exception('e'); // throw an exception echo 2; // not execute
在 PHP 中,Generator 提供了 throw
方法來拋出異常。用法和普通的異常同樣,只不過把 throw
關鍵字改爲了方法調用。異步編程
function gen() { yield 0; yield 1; yield 2; yield 3; } $gen = gen(); $gen->throw(new Exception('e')); // throw an exception var_dump($gen->valid()); // output: false echo 2; // not execute
一樣的,咱們能夠這個異常捕獲,經過 try catch 來進行。函數
try { $gen->throw(new Exception('e')); } catch (Exception $e) { echo $e->getMessage(); // output: e } var_dump($gen->valid()); // output: false echo 2; // output: 2
咱們能夠看到,當咱們使用 throw 拋出異常後,當前的生成器的 valid 變成了 false。可是考慮下面一種狀況,當咱們在外面調用 throw 方法後,在生成器函數中捕獲異常,會發生什麼呢?咱們來看下面的例子。工具
function gen() { yield 0; try { yield; } catch (Exception $e) { echo $e->getMessage(); // output: e } yield 2; yield 3; } $gen = gen(); $gen->next(); // reach the point of catching exception $gen->throw(new Exception('e')); var_dump($gen->valid()); // output: true echo 2; // output: 2
當咱們在生成器函數捕獲來自 throw 方法拋出的異常後,生成器依然是 valid 的。可是若是像剛纔同樣只是在調用 throw 方法,那麼生成器就結束了。code
function gen() { yield 0; throw new Exception('e'); yield 2; yield 3; } $gen = gen(); $gen->next(); $gen->current(); // throw an exception var_dump($gen->valid()); // output: false echo 2; // not execute
以前咱們看到的是調用 throw 方法來拋出異常。那麼在生成器函數中,拋出一個異常而沒有在生成器函數中捕獲,結果也都是同樣的。一樣的,若是在生成器函數中捕獲了異常,那麼就和以前的例子同樣了。協程
在理解了上面的例子以後,咱們就要考慮一下,若是有嵌套的生成器,會發生什麼了。get
當咱們在一個生成器函數中,yield
了另一個生成器函數以後,就會變成嵌套生成器。咱們來看下面的例子。io
function subGen() { yield 1; throw new Exception('e'); yield 4; } function gen() { yield 0; yield subGen(); yield 2; yield 3; } $gen = gen(); $gen->next(); $gen->current()->next(); // throw an exception echo 2; // not execute
對於嵌套的生成器來講,若是子生成器中拋出了異常,那麼在沒有捕獲這個異常的狀況下,會一級一級向上拋出,直到結束。
剛纔咱們嘗試了,在拋出異常以後,valid 的返回值變成了 false。那麼在嵌套生成器中,是否是也是這樣呢?咱們把異常捕獲,使程序可以繼續執行下去,來看下面這個例子。
function subGen() { yield 1; throw new Exception('e'); yield 4; } function gen() { yield 0; yield subGen(); yield 2; yield 3; } $gen = gen(); $gen->next(); try { $gen->current()->next(); } catch (Exceprion $e) { echo $e->getMessage(); //output: e } var_dump($gen->valid()); // output: true echo 2; // output: 2
因此,當子生成器拋出異常後在迭代的過程當中被正常地捕獲,那麼,父生成器便不會受到影響,valid 的返回值依然是 true
。
關於生成器的異常處理,這裏來進行一下總結。
false
;false
;true
;yield 爲咱們提供了使用 PHP 實現半協程的工具。最近在研究使用 yield 實現半協程,而這個過程當中,對異常的處理,是很是重要的。可是 yield 的運行方式決定了異常處理比較難以理解。因而我花了幾天的時間,嘗試了各類可能,得出來的這些結論。固然因爲本人水平有限,若有錯誤,還望指點一二,不勝感激。