2011-02-08 9 views
9

PHPのほとんどのリソースはメモリ管理には触れません。なぜなら、言語自体がこれを行うのにはかなり良いからです。しかし、PHPでは、メモリではない外部リソース(データベースハンドル、セッション、データベーストランザクションなど)を処理することがよくあります。これらの外部リソースは、RAIIオブジェクトの何らかの形式を使用して最もきれいに管理できます。PHPはRAIIパターンをサポートしていますか?どうやって?

私は当初、PHPは、デストラクタの概念が存在しないJVMやCLRに似たガベージコレクションスキームを使用していると考えました。特定の__destructメソッドがありますが、それはJavaまたはC#ファイナライザに似た「ファイナライザ」だと思っていました(覚えています:Everyone thinks about garbage collection the wrong way - ファイナライザはデストラクタではありません)。このため、JVMまたはCLR上でRAIIを使用することはできません(C#のusingブロックでは、その方法の約95%が得られますが、これは少し異なります...)。

ただし、Google seems to indicate that PHP supports the RAII patternですが、これはPHPのドキュメントで確認できません。言語がこれをサポートしていて、RAIIタスクを達成するのに十分なクリーンアップロジックを__destructに入れていますか?

答えて

9

これはほぼIs destructor in PHP predictable?と同じ質問ですが、答えは同じです。 PHPはrefcountingを使用しており、refcountがゼロになるとすぐにデストラクタが呼び出されることを約束しています(通常、オブジェクトがスコープから外れるとき)。したがって、オブジェクトを作成して範囲外に漏らさないように注意すると、RAIIは実行可能です。

+3

もう一つの注意点:複数のオブジェクトを同時にスコープを去るとき、彼らのデストラクタが呼び出される順序が正式に定義されていない、通常はFIFO順に(正確に適切なRAIIのために必要とされるものの反対)。それは私の特定のユースケースのためのデングブレイカーです。 – Brilliand

+0

@Brilliand人工的にカッコを追加して順序付けを強制することはできますか? :) – hobbs

+0

中括弧はそれをしません - 機能だけが新しい範囲を導入することができます。それでも可能だと思いますが、それは定型文の量が多いことになります。 – Brilliand

4

PHPは参照カウントを使用しています。したがって、変数を使用するとすぐにクリーンアップされます。 (サイクルを作成しない限り)リソースを即座に解放するので、メモリサイクルを作成しないように注意する以外に、明示的なリソース管理について一般に心配する必要はありません。

特定の戦略を実装したい場合は、そのリソースが1つの変数でのみ使用されていることを確認することで実行できます。その変数がリソースから離れて指されるときはいつでも、リソースはすぐに解放されるべきです。

2

次のクラスReturnHandlerは、ReturnHandlerのインスタンスが有効範囲外になったときにハンドラを自動的に起動します。あなたの関数(myfunc)には、それぞれの前にリソースを解放することを考える必要がなく、複数のreturnを持つことができます。ここで

/** 
* Automatically calls a handler before returning from a function. Usage: 
* 
* function myfunc() 
* { 
* $resource = new Resource(); 
* $rh = new ReturnHandler(function() use ($resource) { $resource->release(); }); 
* // ... 
* if(...) { 
* return; // look, ma, automatic clean up! 
* } 
* } 
*/ 
class ReturnHandler 
{ 
    private $return_handler; 

    public function __construct($return_handler) 
    { 
    $this->return_handler = $return_handler; 
    } 

    public function __destruct() 
    { 
    $handler = $this->return_handler; 
    $handler(); 
    } 
} 

はそれのためのテストです:

class ReturnHandlerTest extends PHPUnit_Framework_TestCase 
{ 

    private static function trigger_return_handler(&$var) 
    { 
    $rh = new ReturnHandler(function() use (&$var) { $var++; }); 
    } 

    public function test() 
    { 
    $a = 0; 
    $this->assertEquals(0, $a); 
    self::trigger_return_handler($a); 
    $this->assertEquals(1, $a); 
    } 
} 
+0

私はむしろ、ほとんどの使用のために問題のリソースを包むタイプを持っています。しかし、これは迅速で汚れた解決策として機能します。あなたのプログラムで使用されているリソースのインスタンスが1つしかない場合 –

関連する問題