Help us understand the problem. What is going on with this article?

例外オブジェクトはシリアライズ可能か?

More than 5 years have passed since last update.

前提(予備知識)

まず基本的なことから。

  • Closure はシリアライズ出来ない。
  • スタックトレースは trace プロパティに保持される。

trace プロパティ配列の各要素は以下のようなキーを持つ連想配列からなる。 fileline はクロージャ呼び出しに関しては未定義になる。

  • file (ファイル)
  • line (行)
  • function (関数/メソッド/クロージャ)
  • args (引数)

検証

変数に代入して呼び出す

コード
<?php
session_start();
try {
    $func = function () { throw new \Exception; };
    $func();
} catch (\Exception $e) {
    var_dump($e->getTrace());
    $_SESSION['exceptions'][] = $e;
}
結果
array(1) {
  [0]=>
  array(4) {
    ["file"]=>
    string(12) "test.php"
    ["line"]=>
    int(5)
    ["function"]=>
    string(9) "{closure}"
    ["args"]=>
    array(0) {
    }
  }
}

call_user_func 関数で呼び出す

コード
session_start();
try {
    call_user_func(function () { throw new \Exception; });
} catch (\Exception $e) {
    var_dump($e->getTrace());
    $_SESSION['exceptions'][] = $e;
}
実行結果
array(2) {
  [0]=>
  array(2) {
    ["function"]=>
    string(9) "{closure}"
    ["args"]=>
    array(0) {
    }
  }
  [1]=>
  array(4) {
    ["file"]=>
    string(38) "test.php"
    ["line"]=>
    int(4)
    ["function"]=>
    string(14) "call_user_func"
    ["args"]=>
    array(1) {
      [0]=>
      object(Closure)#1 (0) {
      }
    }
  }
}

Fatal error: Uncaught exception 'Exception' with message 'Serialization of 'Closure' is not allowed' in [no active file]:0
Stack trace:
#0 {main}
  thrown in [no active file] on line 0

結果

  • function がクロージャであっても、 "{closure}" という文字列になるので問題なくシリアライズ出来る。
  • args の要素にクロージャが含まれていると、オブジェクトのままなのでシリアライズ出来なくなる。

対策

安全にセッションに格納したいときはスタックトレースを全部潰してしまえば問題ない。

スタックトレースを強制的に空配列にする関数
<?php
function clear_trace_recursive(\Exception $e) {
    static $rp;
    if (!$rp) {
        $rp = new \ReflectionProperty('\Exception', 'trace');
        $rp->setAccessible(true);
    }
    do {
        $rp->setValue($e, []);
    } while ($e = $e->getPrevious());
}
mpyw
古い記事はそのまま参考にしないようにご注意ください
synapse
Synapseは、オンラインサロンサービスにおけるパイオニアとして、かつて存在していたスタートアップです。
https://synapseam.github.io/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away