Yalnızca tek bir bağlantı gerektiren uygulamalar için PHP5'ta DB bağlantı kodu gizlemek için en iyi yolu?

2 Cevap php

Ben tek bir bağlantı dahil olduğunda (bu genellikle üzerinde çalışmak web uygulamaları için böyledir) benim veritabanı erişimi basitleştirmek için üç seçenek sunuyoruz Aşağıda.

Genel bir fikir benim komut bir sorgu yürütür ve komut sonlanana kadar o bağlı kalır ilk defa bağlar şekilde, DB bağlantı saydam hale getirmektir.

Ben neden iyi ve olduğunu düşünüyorum hangisini bilmek istiyorum. Ben bu onları kullanarak için çok üzgünüm uygun olabilecek tasarım desen isimlerini bilmiyorum. Ve PHP5 ile bunu yaparken herhangi bir better yolu varsa, lütfen paylaşın.

Kısa bir giriş vermek: Bir sorgu yöntemini içeren bir DB_Connection sınıf var. Bu kimin arayüz Bu örneğin amacıyla basitleştirilmiş ettik benim kontrolüm ve dışında bir üçüncü taraf sınıftır. Her seçeneğin ben de bazı bağlam vermek için bir hayali DB "ürün" tablosu için örnek bir model sağladık.

Seçenek 3 Benim en çok sevdiğim arayüzü ile bana sağlayan biridir, ama ne yazık ki pratik sanmıyorum.

Ben aşağıda açıklama bloklarında her artılarını ve (görebildiğim) eksileri tarif ettik.

Yükü benim DB sarıcı sınıf yerine modellerinde koymak olduğundan şu anda ben Seçenek 1 meyledeceğini.

Tüm yorumlar takdir!

Not: Nedense yığın taşması yerine önizleme çizgi bir kodlanmış HTML varlık gösteriyor. Sonrası böyle yoluyla gelirse, bunu dikkate lütfen.

<?php

/**
 * This is the 3rd-party DB interface I'm trying to wrap.
 * I've simplified the interface to one method for this example.
 *
 * This class is used in each option below.
 */
class DB_Connection {
    public function &query($sql) { }
}

/**
 * OPTION 1
 *
 * Cons: Have to wrap every public DB_Connection method.
 * Pros: The model code is simple.
 */
class DB {
    private static $connection;
    private static function &getConnection() {
        if (!self::$connection) {
            self::$connection = new DB_Connection();
        }
        return self::$connection;
    }
    public static function &query($sql) {
        $dbh = self::getConnection();
        return $dbh->query($sql);
    }
}

class Item {
    public static function &getList() {
        return DB::query("SELECT * FROM items");
    }
}

/**
 * OPTION 2
 *
 * Pros: Don't have to wrap every DB_Connection function like in Option 1
 * Cons: Every function in the model is responsible for checking the connection
 */

class DB {
    protected static $connection = null;
    public function connect() {
        self::$connection = new DB_Connection();
    }
}

class Item extends DB {
    public static function &getList() {
        if (!self::$connection) $this->connect();
        return self::$connection->query("SELECT * FROM items");
    }
}

/**
 * OPTION 3
 *
 * Use magic methods
 *
 * Pros: Simple model code AND don't have to reimplement the DB_Connection interface
 * Cons: __callStatic requires PHP 5.3.0 and its args can't be passed-by-reference.
 */
class DB {
    private static $connection = null;

    public static function &getConnection() {
        if (!self::$connection) {
            self::$connection = new DB_Connection();
        }
        return self::$connection;
    }

    public static function __callStatic($name, $args) {
        if (in_array($name, get_class_methods('DB_Connection'))) {
            return call_user_func_array(
                array(self::getConnection(), $name), $args);
        }
    }
}

2 Cevap

(Sizin için basit bir SELECT, daha bir saklı yordam çağrısı için farklı başarısız isteyebilirsiniz sadelik her zaman kazanır ve yöntemine bağlı olarak başarısız bir bağlantı farklı işleyebilir - Yukarıdaki örneklere dayanarak, seçenek 1 iyi olduğunu söyleyebilirim örneği).

Semantik bir kaynak olarak DB tedavi eğer ben, seçenek 1 en mantıklı düşünmek konuşan o DB_Connectioin o nesnenin kendisi mutlaka ama kullanan bir nesnedir.

Ancak, bazı şeyler ben karşı dikkatli olun. İlk olarak, şiddetle kodu test yeteneğinizi etkileyecek gibi DB sınıf tüm statik yöntemleri var yapmazlar. Bunun yerine bu gibi kontrol konteyner çok basit bir inversiyon düşünün:

class DB {
    private $connection;
    public function &query($sql) {
        return $connection->query($sql);
    }
    public __construct(&$db_connection) {
        $this->connection = $db_connection;
    }
}

class Item {
    public function &getList() {
        return  ResourceManager::getDB()->query("SELECT * FROM items");
    }
}

class ResourceManager {
    private $db_connection;
    private function &getDbConnection() {
        if (!$this->connection) {
            $this->connection = new DB_Connection();
        }
        return $this->connection;
    }
    private $db;
    public static function getDB() {
        if(!$this->db) $this->db = new DB(getDbConnection());
    return $this->db;
}

Önemli faydaları vardır. DB singleton olarak kullanılacak istemiyorsanız sadece ResourceManager bir değişiklik yapmak. Eğer karar verirseniz bir tek olmamalı - Eğer bir yerde değişiklik yapmak. Bazı bağlamına dayalı DB farklı bir örneğini dönmek istiyorsanız - yine değişiklik yalnızca tek bir yerde.

Şimdi DB izolasyon Öğe test etmek istiyorsanız, sadece ResourceManager bir setDb ($ db) yöntemi oluşturmak ve sahte / sahte veritabanı (simplemock bu konuda size iyi hizmet edecek) ayarlamak için kullanın.

Ikinci - ve bu tasarım kolaylaştırır başka modifikasyon - olmak gerekmez daha size veritabanı bağlantısı tüm zaman açık tutmak istemeyebilirsiniz, bu çok daha fazla kaynak kullanarak sona erebilir.

Eğer DB_Connection gösterilmeyen başka yöntemleri de var söz olarak sadece bir bağlantı korunarak fazla kullanılıyor olabilir gibi Son olarak, öyle görünüyor. Eğer bunun üzerinde hiçbir kontrole sahip söylüyorlar beri, ben umurumda DO yöntemleri ondan bir arayüz ayıklanması ve bir MyDBConnection sizin arabirimini uygulayan DB_Connection sınıfını genişleten yapma tavsiye olabilir. Benim durumumda böyle bir şey sonuçta da bazı ağrı kolay olacaktır.