2011-09-10 34 views
6

Tất cả các mẫu đơn tôi đã thấy sử dụng tham chiếu đến đối tượng để xác định xem đối tượng đã được khởi tạo chưa. Tuy nhiên, nếu tôi đang sử dụng một singleton để đảm bảo chỉ có một kết nối db, tại sao không sử dụng liên kết tài nguyên kết nối db để làm điều này? Đây là mã tôi đang sử dụng. (PS: nó hoạt động tốt). Tôi sử dụng bình luận để có thể dễ dàng tìm kiếm các lớp của tôi.Một singleton đơn giản

/*one*/ 

class one 
    { 
    public static $db; 
    private function __construct() 
    { 
    self::$db=new mysqli(DB_HOST, DB_USER, DB_PASS, DB_DATABASE); 
    } 
    public static function get() 
    { 
    if(self::$db==NULL) 
     { 
     new self(); 
     } 
    return self::$db; 
    } 
    } 
+1

+1 cho sự khéo léo! – Clive

+1

Vẫn còn là singleton. Không có gì bất thường ở đó, tôi nói. – Smar

+2

Errr ... Không ai thấy rằng phương thức get trả về một đối tượng khác? – Macmade

Trả lời

5

Trong PHP, một constructor không trả lại.

Vì vậy, phương thức get trả về đối tượng one, lần đầu tiên được gọi, sau đó là đối tượng mysqli. Có lẽ không phải những gì bạn muốn.

if(self::$_db == NULL) 
{ 
    return new self(); // Here you return an object of class one 
} 
else 
{ 
    return self::$_db; // Here you return an object of type mysqli 
} 

Nếu bạn muốn trả lại đối tượng mysqli, bạn không cần một singleton, như không có nhu cầu để tạo ra một thể hiện của một đối tượng mà chỉ đây để trở về một thể hiện của đối tượng khác.

Mẫu đăng ký sẽ tốt hơn trong trường hợp này.

Nếu bạn cần cung cấp các phương thức (trình bao bọc cho đối tượng DB của bạn), sau đó tạo một singleton thực.

EDIT

Tôi đã kiểm tra mã được cập nhật. Bây giờ bạn luôn quay trở lại phiên bản mysqli. Nhưng bạn không cần phải khởi tạo đối tượng của riêng bạn. Điều đó hoàn toàn vô dụng ...

Nếu bạn thực sự muốn đi với loại hình của bạn, như vàng nói, trong trường hợp tĩnh của bạn, kiểm tra xem self::dbNULL. Nếu có, hãy tạo cá thể mysqli và gán nó cho self::db. Sau đó trả lại nó.

public static getDatabaseInstance() 
{ 
    if(self::$_db == NULL) 
    { 
     self::$_db = new mysqli(...); 
    } 

    return self::$_db; 
} 

Cũng đặt hàm tạo riêng tư, vì vậy người dùng sẽ không thể tạo các phiên bản vô dụng của lớp học của bạn. Hoặc tốt hơn làm cho nó công cộng và ném một ngoại lệ:

public function __construct() 
{ 
    throw new Exception('This class is not supposed to be instantiated'); 
} 
+0

Từ tài liệu PHP: 'void __construct ([mixed $ args [, $ ...]])'. Xem 'void'? http://php.net/manual/en/language.oop5.decon.php – Macmade

+1

Điều đó có nghĩa là giá trị trả lại bị bỏ qua. Vì vậy, ngay cả khi bạn trả về một cái gì đó (một đối tượng khác), nó sẽ không sửa đổi kiểu đối tượng được khởi tạo bởi 'new'. – Macmade

+0

Xem chỉnh sửa của tôi ...:) – Macmade

0
class one 
{ 
    private static $_selfInstance; 
    public $db; 
    private function __construct() 
    { 
    } 
    public function getDb() 
    { 
     if($this->db == null) 
     $this->db=new mysqli(DB_HOST, DB_USER, DB_PASS, DB_DATABASE); 
     return $this->db; 

    } 

    public static function getInstance() 
    { 
     if(!(self::$_selfInstance instanceof self)) { 
     self::$_selfInstance= new self(); 
     } 
     return self::$_selfInstance; 
    } 
} 

Tiếp cận

$db = one::getInstance()->getDb(); 
+1

Có lý do nào để loại bỏ 'n' thứ hai trong' $ _selfInstace' không? – jcolebrand

1

Giả sử tôi đang phân tích câu hỏi của bạn một cách chính xác, bạn đang yêu cầu nếu nó okay để sử dụng vô hiệu của $db để đảm bảo rằng bạn chỉ thể hiện hóa một; đó là một cách hoàn toàn hợp lệ để làm mọi thứ, và trên thực tế là những gì tôi muốn giới thiệu. PHP null được định nghĩa rõ ràng để đại diện cho một biến với "không có giá trị" - một sự phù hợp hoàn hảo cho trạng thái uninitialized của mẫu đơn.

Thông thường, những thứ này sẽ chỉ được gọi bằng tên trực quan, ví dụ: SomeAppDbConn.

0

Như Macmade đã chỉ ra, phương thức constructor không trả về bất cứ điều gì ngoại trừ một thể hiện của lớp. Giả sử bạn luôn muốn có cùng một thể hiện của mysqli, đây là cách tôi làm điều đó.

class DBInstance 
{ 
    protected static $db; 

    private function __construct() 
    { 
     // intentionally empty 
    } 

    public static function get() 
    { 
     if(self::$db === NULL) 
     { 
      self::$db=new mysqli(DB_HOST, DB_USER, DB_PASS, DB_DATABASE); 
     } 

     return self::$db; 
    } 
} 

Nó chắc chắn nhất là một mẫu đơn với tiền thưởng bổ sung là tách phân biệt khỏi lớp đã được khởi tạo.

+0

Đăng ký sẽ tốt hơn, IMHO. Hoặc ít nhất, tuyên bố các nhà xây dựng tư nhân, để tránh instanteless vô dụng của lớp. – Macmade

+0

Bạn và tôi đồng ý với bạn về việc sử dụng đăng ký. Mặt khác, việc sử dụng phương pháp này chắc chắn nhanh hơn nếu bạn đang phát triển một ứng dụng thực sự nhỏ, nơi kết nối cơ sở dữ liệu chỉ phù hợp với mẫu này. Bạn nghĩ sao? – gilden

+0

Chắc chắn, và có vẻ như anh ấy muốn nó theo cách đó ...:) – Macmade

3

Xác định nó hoạt động tốt :)

Cố gắng:

  • so sánh băm đối tượng trở về từ cả hai phương pháp (không thành vấn đề khi bạn sử dụng đối tượng nhân bản)
  • kết nối với DB sử dụng thông tin đăng nhập khác nhau (ví dụ: trong các bài kiểm tra đơn vị)
  • ngắt kết nối khỏi DB và kết nối lại một lần nữa
  • đặt lại phiên bản của đối tượng (bây giờ tạo 1000 đối tượng bằng cách sử dụng new lấp đầy bộ nhớ)
  • yêu cầu một số nhà phát triển khác tạo ví dụ của lớp này, anh ấy chắc chắn sẽ tìm phương thức one::getInstance(). Làm thế nào để anh đoán được hành vi của lớp này?

Độc giả về trạng thái toàn cầu. Hình như ở đây bạn có trạng thái toàn cầu + một số mớ hỗn độn.