Wednesday, July 20, 2011

Singleton design pattern in PHP

You can find all the information you need on the web if you google singleton design pattern. So I'm not gonna fill your head with all the theory.

I'll tell you how you can implement it.



So, we have a application that lists the products from the database. To do this, we have a class named 'Product'.

class Product{
    public $_data;

    function __construct($id = 0){
        if($id != 0)
            $this->loadProduct($id);
    }

    function loadProduct($id){
        if(!$id) 
            return;
        $this->_data = mysql_fetch_array(
                       mysql_query("SELECT * FROM products WHERE id = ".intval($id))
                );
    }
}

This is a basic method of selecting a product from the database.

Now, if we select the product just once, there's no problem. But if our product appears on more then one part of the site, let's say for meta info, for special products on the right side, instantiating our class for 3 times consumes many resources and time.

The idea is to keep out instances in a static variable, and to use that variable to return the already selected product. Now the program uses less resources and is faster.

To do this for our class, we need a static method, called by default (so other programmers know what is about) "getInstance".

class Product {
    static $_instances;
    
    public $_data;
    
    private function __construct($id = 0){
        if($id != 0)
            $this->loadProduct($id);
    }
    
    public function loadProduct($id){
        ...
    }
    
    public static function getInstance($id){
        if(!array_key_exists($id,self::$_instances)
               || !(self::$_instances[$id] instanceof self) ){
            self::$_instances[$id] = new self($id);
        }
        return self::$_instances[$id];
    }
}

So we have a static variable $_instances declared in the class. We do this because we might need that variable to be visible across the class, for other methods like one that checks if that product is already instantiated. This helps if you want to be sure that the product is not listed twice in the site - like once in the product listing page, and twice in the column that shows the special offers.

I put the constructor private to make sure another instance of the class cannot be made.

This is a very useful method, but not for all objects. It is useful for the database class (in combination with factory design patters, which I'll explain at another time), for session class (this too is better with factory), for product class, basically for any class that might be used all over the site. It is not very useful at a pagination class for example.

Have fun

No comments:

Post a Comment