2011-02-08 29 views
9

Hầu hết các tài nguyên trên PHP không bao giờ chạm vào quản lý bộ nhớ vì ngôn ngữ chính nó là khá tốt khi làm điều này cho bạn. Tuy nhiên, trong PHP bạn thường kết thúc với các tài nguyên bên ngoài mà không phải là bộ nhớ - xử lý cơ sở dữ liệu, phiên, giao dịch cơ sở dữ liệu, vv Các tài nguyên bên ngoài này có thể được quản lý một cách rõ ràng nhất bằng cách sử dụng một số đối tượng RAII. Ban đầu tôi nghĩ rằng PHP đã sử dụng một lược đồ thu gom rác tương tự như JVM hoặc CLR, trong đó khái niệm về một destructor không tồn tại. (Hãy nhớ rằng: Everyone thinks about garbage collection the wrong way - finalizers không destructors!) Có phương pháp đặc biệt __destruct, nhưng tôi nghĩ rằng đó là một "finalizer" tương tự như một Java hoặc C# finalizer. Vì lý do này, bạn không thể sử dụng RAII trên JVM hoặc CLR (C# 's using khối giúp bạn có được khoảng 95% cách đó, nhưng đó là một chút khác nhau ...).PHP có hỗ trợ mẫu RAII không? Làm sao?

Tuy nhiên, Google seems to indicate that PHP supports the RAII pattern, mặc dù tôi không thể tìm thấy xác minh điều này trong tài liệu PHP. Ngôn ngữ có hỗ trợ điều này và đang đặt logic dọn dẹp trong __destruct đủ để hoàn thành các tác vụ RAII không?

Trả lời

9

Câu hỏi này gần như giống với câu hỏi Is destructor in PHP predictable? và câu trả lời giống nhau. PHP sử dụng refcounting, và nó hứa hẹn rằng destructor sẽ được gọi ngay lập tức ngay khi refcount đi đến số không (thường khi đối tượng ra khỏi phạm vi). Vì vậy, nếu bạn tạo một đối tượng và cẩn thận không rò rỉ nó ra khỏi phạm vi, RAII là khả thi.

+3

caveat Một: khi nhiều đối tượng rời khỏi phạm vi cùng một lúc, trình tự hủy của họ được gọi là chính thức không xác định, và thường theo thứ tự FIFO (chính xác đối diện với những gì cần thiết cho RAII thích hợp). Đó là một dealbreaker cho trường hợp sử dụng cụ thể của tôi. – Brilliand

+0

@Brilliand bạn có thể thêm một cách giả tạo niềng răng để thực thi thứ tự? :) – hobbs

+0

Niềng răng sẽ không làm điều đó - chỉ một chức năng mới có thể giới thiệu một phạm vi mới. Vẫn có thể, tôi cho rằng, nhưng điều đó có thể dẫn đến rất nhiều boilerplate. – Brilliand

4

PHP sử dụng tính tham chiếu, vì vậy khi bạn hoàn thành một biến, nó sẽ được xóa ngay lập tức. (Trừ khi bạn tạo chu kỳ.) Điều đó giải phóng tài nguyên kịp thời để bạn thường không cần phải lo lắng về quản lý tài nguyên rõ ràng ngoài việc cẩn thận để không tạo chu kỳ bộ nhớ.

Nếu bạn muốn thực hiện bất kỳ chiến lược cụ thể nào, bạn có thể thực hiện bằng cách đảm bảo rằng tài nguyên chỉ được sử dụng bởi một biến. Bất cứ khi nào biến đó được chỉ ra khỏi tài nguyên, tài nguyên sẽ được giải phóng ngay lập tức.

2

Lớp sau ReturnHandler cung cấp tự động gọi trình xử lý khi cá thể ReturnHandler vượt quá phạm vi. Bạn có thể có một số return s trong chức năng của bạn (myfunc) mà không cần phải suy nghĩ về việc phát hành tài nguyên trước mỗi người trong số họ.

/** 
* 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(); 
    } 
} 

Dưới đây là một thử nghiệm cho nó:

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

Tôi muốn có loại kết thúc tốt hơn tài nguyên được đề cập trong hầu hết các lần sử dụng. Nhưng điều này sẽ hoạt động như một giải pháp nhanh chóng và bẩn thỉu, ví dụ: nếu bạn chỉ có một cá thể của một tài nguyên cụ thể được sử dụng trong chương trình của bạn. –