【PHP】finally 内のコードが実行されないパターンと対策

  • 2021年7月19日
  • 2021年7月20日
  • PHP

 finally はある処理が終わった後、例外が投げられる投げられないに関わらず必ず実行されるコードが記述される部分です。

finally

catch ブロックの後に
finally ブロックも指定できます。
finally ブロックの何かに書いたコードは、
try および catch ブロックの後で常に実行されます。
例外がスローされたかどうかは関係ありません。

PHP: 例外(exceptions) – Manual

 このため finally の中にコードを書いたならば、一度 try の中に入った後に必ず実行される気がします。しかしながら、実行されないパターンもあります。これは try 実行後、finally 実行前の間に PHP プロセスが終了するパターンです。これは次のコードで確認できます。

<?php

try{
    echo 'in try'. "\n";// in try は出力されます
    exit();
}finally{
    echo 'in finally';// in finally は出力されません
}

Online PHP editor | output for TFPmS

 これは外部からのプロセスキルでも起き得ます。このため finally よりも確実に実行されるコードの書き方の需要があります。これは次の様な __invoke, __construct, __destruct による関数的に動作するクラスで実現できます。__invoke はクラスインスタンスを関数的に使うためのマジックメソッドです。

<?php

class Func
{
    public function __construct(){
        echo 'construct'."\n";
    }
    
    public function __invoke(){
        echo 'invoke'."\n";
    }
    
    public function __destruct(){
        echo 'destruct'."\n";
    }
}

$f = new Func(); // construct が出力
$f();// invoke が出力
echo 'exit before'."\n"; // exit before が出力
exit(); // destruct が出力
echo 'exit after'."\n"; // ここから先は出力されない
var_dump($f);

Online PHP editor | output for WLE8F

PHP: コンストラクタとデストラクタ – Manual
destruct は通常のプログラムのフローと違ったタイミングで動作します(順番にコードを追うだけでは通らない)。動作するのは参照不能になった時、スクリプトが終了する時です。このタイミングは順不同であるため、オブジェクトが保持されているプロパティは使わずに素の PHP でその場で完結するコードを書くなどした方が安全です。
 デストラクタの実行を明示的に通常フローの制御下に置くには unset が便利です。

<?php

class Func
{
    public function __construct(){
        echo 'construct'."\n";
    }
    
    public function __invoke(){
        echo 'invoke'."\n";
    }
    
    public function __destruct(){
        echo 'destruct'."\n";
    }
}

$f = new Func(); // construct が出力
$f();// invoke が出力

unset($f);  // destruct が出力

echo 'exit before'."\n"; // exit before が出力
exit();
echo 'exit after'."\n"; // ここから先は出力されない
var_dump($f);

 書き方や挙動がいささか複雑ですが、クリティカルな部分であったり、プロセスキルが十分ありうる環境であったりするならばデストラクタによる後始末処理は十分作る価値があります。

>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG