2011-10-21 17 views
10

私は例外ハンドラを持つスクリプトを持っています。この例外ハンドラは、例外後にスクリプトが終了する前に、いくつかの接続をクリーンアップします。例外ハンドラ内で例外を投げる

この例外ハンドラから例外を再スローして、PHP独自の最後の例外ハンドラによって処理されるようにします。エラーハンドラは、エラーがPHPのエラーログに書き込まれるか、デフォルトで設定されていますPHP.ini。ここに概説されているよう

残念ながら、これは、可能性のように見えるしていません:バブルへのもう一つの方法は、スタックがエラー

http://www.php.net/manual/en/function.set-exception-handler.php#68712

Will cause a Fatal error: Exception thrown without a stack frame

がアップしているので、PHPは、私の例外の後、それを処理しますハンドラはクリーンアップされていますか?

+0

を維持しますrを計算し、エラーをログに記録します。 – netcoder

+0

あなたのハンドラから[もう一度例外をスローする](http://stackoverflow.com/questions/7856173/throwing-exception-within-exception-handler/7939492#7939492)はどうですか?方法が分かっていれば動作しますそして、あなたが探しているPHPの最後のリゾートハンドラを起動します。 – hakre

+0

私は以前これを見てきましたが(エラーハンドラの復元をお勧めします)、今は再現できません!この問題は、PHP/.iniの設定の一部になっていますか? – jlb

答えて

12

例外ハンドラから再スローすることはできませんが、他にも可能です。たとえば、あなたは、それ自身のクラスに物事をカプセル化することによって、ハンドラからの再スローを夫婦-解除してから__destruct()機能(PHP 5.3、Demo)を使用することができます。

<?php 

class ExceptionHandler 
{ 
    private $rethrow; 
    public function __construct() 
    { 
     set_exception_handler(array($this, 'handler')); 
    } 
    public function handler($exception) 
    { 
     echo "cleaning up.\n"; 
     $this->rethrow = $exception; 
    } 
    public function __destruct() 
    { 
     if ($this->rethrow) throw $this->rethrow; 
    } 
} 

$handler = new ExceptionHandler; 

throw new Exception(); 

は私のエラーログにこれを入れて:

[29-Oct-2011 xx:32:25] PHP Fatal error: Uncaught exception 'Exception' in /.../test-exception.php:23 
Stack trace: 
#0 {main} 
thrown in /.../test-exception.php on line 23 
+1

'__destruct'についていくらか関連しています:[PHPスクリプトが終了段階にあることを確認する方法](http://stackoverflow.com/q/6227611/367456) – hakre

+0

ありがとう@hakre、あなたソリューションが機能します。私が望んでいた以上の回避策がありましたが、なぜこれが必要なのか理解しています。 – Brad

+0

ねえ、ブラッド、受け入れてくれてありがとう。私はこの "回避策"のほうが、php.netのユーザコメントに対する提案よりも、自分自身のエラーログエントリを作成するほうが好きです。なぜホイールを再発明するのですか?私はレジスタシャットダウン機能も試しましたが、ここで私はより良いのが好きです。 – hakre

6

例外をキャッチしてメッセージを自分で記録してから、再度ログインしてください。あなたのトップまでのバブルとPHPが処理できない場合

try { 
    $foo->doSomethingToCauseException(); 
} catch (Exception $e) { 
    error_log($e->getMessage()); 
    throw $e; 
} 

、それがキャッチされない例外が発生します。

+0

キャッチされない例外が私には問題ありません。私はトップまですべてをバブルしたい。私はあなた自身で今はエラーを記述しています(あなたが記述している正確なメソッドを使用しています)。しかし、一貫性のためにPHPがそれを扱えるようにします。 – Brad

+0

私は参照してください。私はこれについても好奇心が強いです。私の経験上、PHPが例外を処理する唯一の方法は、ページを爆発させることです。 –

3

Will cause a Fatal error: Exception thrown without a stack frame

このエラーは、例外が(限りPHPは知っている)スクリプトの一部ではないコードからスローされることを意味しています。このようなコードの例には、set_exception_handler()および任意のクラスデストラクタメソッドで設定されたカスタム例外ハンドラが含まれます。このようなコードから例外をスローしないでください。

PHPのネイティブエラー処理が必要な場合は、代わりにtrigger_error()に電話することをおすすめします。カスタムエラーハンドラがなく、適切なエラータイプを使用する場合は、エラーを記録する必要があります。たとえば、E_USER_ERRORは問題ありません。

+0

また、設定によっては正しいバックトレースが得られますが、[例外をもう一度スローしてください](http://stackoverflow.com/questions/7856173/throwing-exception-within-exception-handler/7939492#7939492)。 – hakre

+0

hakre:ちょうどそれを試してみてください(カスタム例外ハンドラやクラスデストラクタメソッドの中から*何かを投げてください) - うまくいきません。 xdebugを使うかどうかは関係ありません。 –

+1

Mikko、[私の答え](http://stackoverflow.com/questions/7856173/throwing-exception-within-exception-handler/7939492#7939492)にはPHP 5.3が必要です。参照してくださいhttp://codepad.viper-7.com/jamrqP – hakre

1

ただのRuntimeExceptionとして例外を再スローし、それはまだ致命的なERROをトリガするカスタム例外ハンドラを使用してスタックトレース:)

try { 
    // bad exception throwing code 
} catch (Exception $e) { 
    throw new RuntimeException($e->getMessage(), $e->getCode(), $e); 
}