finally はある処理が終わった後、例外が投げられる投げられないに関わらず必ず実行されるコードが記述される部分です。
このため 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);
書き方や挙動がいささか複雑ですが、クリティカルな部分であったり、プロセスキルが十分ありうる環境であったりするならばデストラクタによる後始末処理は十分作る価値があります。