web-dev-qa-db-ja.com

PHP __destruct()メソッドが呼び出されることを信頼できますか?

PHP5では、__ destruct()メソッドが各オブジェクトインスタンスに対して呼び出されることが保証されていますか?プログラムの例外により、これが起こらないようにすることはできますか?

42
Casey Watson

デストラクタは、すべての参照が解放されたとき、またはスクリプトが終了したときに呼び出されます。これは、スクリプトが正常に終了したことを意味すると思います。重大な例外はデストラクタが呼び出されることを保証しないと私は言うでしょう。

PHPのドキュメント は少し薄いですが、デストラクタでの例外により問題が発生すると言われています。

36
Geoff

独自のデストラクタを持つサブクラスの場合、親デストラクタはnotが自動的に呼び出されることにも言及する価値があります。

親クラスが必要なクリーンアップを行う場合は、サブクラス__ destruct()メソッドからparent :: __ destruct()を明示的に呼び出す必要があります。

44
Mark Biek

私の経験では、デストラクタは常にPHP 5.3で呼び出されますが、コードの一部がexit()を呼び出すか、致命的なエラーが発生した場合、PHPは "任意の」順序(実際の順序はメモリ内の順序またはメモリがオブジェクト用に予約された順序だと思います。実際には、この順序はほとんど常に問題があります)。これは、PHPドキュメントでは「シャットダウンシーケンス」と呼ばれています。

デストラクタのPHPドキュメント はこう言っています:

PHP 5では、C++などの他のオブジェクト指向言語と同様のデストラクタの概念が導入されています。デストラクタメソッドは、特定のオブジェクトへの参照がなくなるとすぐに、またはシャットダウンシーケンス中に任意の順序で呼び出されます。

その結果、Yへの参照を保持するクラスXがある場合、Xのデストラクタは、Yのデストラクタが既に呼び出された後に呼び出される可能性があります。うまくいけば、Yへの参照はそれほど重要ではありません...正式に文書化されているため、これはバグではありません。

ただし、公式にPHPはデストラクタが正常に呼び出されている(デストラクタが正しい順序で呼び出されている)か、デストラクタがデータを使用できない「任意の」順序で呼び出されているかを確認する方法を提供していないため、この問題の回避策は非常に困難です。参照されたオブジェクトは既に破棄されている可能性があるためです。 debug_backtrace()を使用してこの検出の欠如を回避し、スタックを調べることができます。通常のスタックの欠如は、PHP 5.3の「シャットダウンシーケンス」を意味するようですが、これも未定義です。循環参照がある場合、これらのオブジェクトのデストラクタはPHP 5.2以下では呼び出されず、PHPの「シャットダウンシーケンス」中に「任意の」順序で呼び出されます5.3以上。循環参照の場合、論理的に「正しい」順序は存在しないため、「任意の」順序がそれらに適しています。

いくつかの例外があります(結局これはPHPです):

  • exit()が別のデストラクタで呼び出された場合、残りのデストラクタは呼び出されません( http://php.net/manual/en/language.oop5.decon.php
  • FATALエラーがどこかで発生した場合(他のデストラクタから例外をスローしようとするなど、考えられる多くの原因が1つの原因である可能性があります)、残りのデストラクタは呼び出されません。

もちろん、PHPエンジンがセグメンテーション違反をヒットしたり、その他の内部バグが発生したりすると、すべての賭けは無効になります。

「シャットダウンシーケンス」のcurrent実装を理解したい場合は、 https://stackoverflow.com/a/14101767 を参照してください。この実装は、将来のPHPバージョンで変更される可能性があることに注意してください。

13

現在、destructメソッドが暗黙的に呼び出されないようにする循環参照のバグがあります。 http://bugs.php.net/bug.php?id=33595 5.3で修正する必要があります

10
MOdMac

確実に実行したい場合は、シャットダウン関数を使用してください: register_shutdown_function()

8
zupa