Do You PHP はてブロ

Do You PHPはてなからはてブロに移動しました

Request for Comments: Supports finally keywordを和訳してみた

先日PHP5.5.0α1がリリースされましたが、ようやくfinallyサポートが入ったようです。

Javaとか使ったことある人にはお馴染みですが、何でtry/catchをサポートした時に入れなかったのか不思議なぐらいです。

ということで、PHP WikiにあるRFCをざっと和訳してみました。また、githubにも上げてありますので、間違いがあればそっちを直して貰えればと。

導入

このRFCは、FR #32100, #36779でリクエストされた例外発生時の 'finally' サポートについての導入です。
この機能がない場合、利用者は処理できない例外が発生した時に以下のような後処理を行うコードを記述しなければなりません。

<?php
$db = mysqli_connect();
try {
   call_some_function($db);
} catch (Exception $e) {
   mysqli_close($db);
   throw $e;
}
mysql_close($db);

finallyを導入することは、このような状況で1,2行短くすることではなく、このような問題を処理するためのより正しい方法を提供することです。

提案

finallyブロックはtryブロックが終了するときに常に実行されます。これは、finallyブロックが予期しない例外が発生した場合でも実行される、ということを保証します。しかし、finallyはただ例外処理のためだけではなく、より有効です。たとえば、returnやcontinue、breakによって後処理のコードが迂回されるのを防ぐ、といったことです。finallyブロックに後処理コードを記述することは常に、たとえ例外が予測されていない場合でさえも、良いプラクティスです。

<?php
$db = mysqli_connect();
try {
   call_some_function($db);//この関数は処理できない例外を投げるかも知れない
} finally {
   mysqli_close($db);
}

最も間違えやすい部分は "try/catchブロック中のreturn"です。この場合でもfinallyブロックはコールされます。

<?php
  try {
    return 2;
  } finally {
    echo "this will be called\n";
  }
  //ここは決してコールされない
  echo "you can not see me";

上のスクリプトは以下のように出力します:

this will be called
//return int(2)

また、以下のようなネストしたtry catch finally:

<?php
function foo ($a) {
   try {
      echo "1";
      try {
        echo "2";
        throw new Exception("ex");
      } catch (Exception $e) {
        echo "3";
      } finally {
        echo "4";
        throw new Exception("ex");
      } 
   } catch (Exception $e) {
      echo "3";
   } finally {
      echo "2";
   }
   return 1;
}

var_dump(foo("para"));

では、以下のように出力されます:

123432int(1)


以下にあるTests & Examplesセクションに、多くのエッジケースについての例があります。