Mysql
 sql >> डेटाबेस >  >> RDS >> Mysql

PHP पीडीओ के लिए सिंगलटन विकल्प

सिंगलटन-पैटर्न (या एंटीपैटर्न) का उपयोग करना बुरा अभ्यास माना जाता है क्योंकि यह आपके कोड का परीक्षण बहुत कठिन बना देता है और जब तक परियोजना किसी बिंदु पर प्रबंधन करना मुश्किल नहीं हो जाता तब तक निर्भरता बहुत जटिल हो जाती है। आपके पास प्रति php-प्रक्रिया में आपके ऑब्जेक्ट का केवल एक निश्चित उदाहरण हो सकता है। अपने कोड के लिए स्वचालित इकाई-परीक्षण लिखते समय आपको उस ऑब्जेक्ट को प्रतिस्थापित करने में सक्षम होना चाहिए जिस कोड का आप परीक्षण करना चाहते हैं, परीक्षण-डबल के साथ उपयोग करता है जो एक अनुमानित तरीके से व्यवहार करता है। जब आप जिस कोड का परीक्षण करना चाहते हैं, वह सिंगलटन का उपयोग करता है, तो आप उसे परीक्षण डबल से नहीं बदल सकते।

ऑब्जेक्ट्स (जैसे आपके डेटाबेस-ऑब्जेक्ट और डेटाबेस का उपयोग करने वाली अन्य ऑब्जेक्ट्स) के बीच बातचीत को व्यवस्थित करने का सबसे अच्छा तरीका (मेरे ज्ञान के लिए) निर्भरताओं की दिशा को उलटना होगा। इसका मतलब है कि आपका कोड उस वस्तु का अनुरोध नहीं कर रहा है जिसकी उसे बाहरी स्रोत से आवश्यकता है (ज्यादातर मामलों में आपके कोड से स्थिर 'get_instance' विधि की तरह एक वैश्विक) लेकिन इसके बजाय इसकी निर्भरता-वस्तु (जिसे इसकी आवश्यकता होती है) बाहर से परोसा जाता है इससे पहले कि उसे इसकी आवश्यकता हो। आम तौर पर आप एक निर्भरता-इंजेक्शन प्रबंधक/कंटेनर का उपयोग करेंगे जैसे यह सिम्फनी प्रोजेक्ट से एक अपनी वस्तुओं की रचना करने के लिए।

डेटाबेस-ऑब्जेक्ट का उपयोग करने वाली वस्तुओं को निर्माण पर इंजेक्ट किया जाएगा। इसे या तो सेटर विधि द्वारा या कंस्ट्रक्टर में इंजेक्ट किया जा सकता है। ज्यादातर मामलों में (सभी नहीं) कंस्ट्रक्टर में निर्भरता (आपकी डीबी-ऑब्जेक्ट) को इंजेक्ट करना बेहतर होता है क्योंकि इस तरह डीबी-ऑब्जेक्ट का उपयोग करने वाली वस्तु कभी भी अमान्य स्थिति में नहीं होगी।

उदाहरण:

interface DatabaseInterface
{
    function query($statement, array $parameters = array());
}

interface UserLoaderInterface
{
    public function loadUser($userId);
}

class DB extends PDO implements DatabaseInterface
{
    function __construct(
        $dsn = 'mysql:host=localhost;dbname=kida',
        $username = 'root',
        $password = 'root',
    ) {
        try {
            parent::__construct($dsn, $username, $password, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'");
            parent::setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        } catch(PDOException $e) {
            echo $e->getMessage();
        }
    }

    function query($statement, array $parameters = array())
    {
        # ...
    }
}

class SomeFileBasedDB implements DatabaseInterface
{
    function __construct($filepath)
    {
        # ...
    }

    function query($statement, array $parameters = array())
    {
        # ...
    }
}

class UserLoader implements UserLoaderInterface
{
    protected $db;

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

    public function loadUser($userId)
    {
        $row = $this->db->query("SELECT name, email FROM users WHERE id=?", [$userId]);

        $user = new User();
        $user->setName($row[0]);
        $user->setEmail($row[1]);

        return $user;
    }
}

# the following would be replaced by whatever DI software you use,
# but a simple array can show the concept.


# load this from a config file
$parameters = array();
$parameters['dsn'] = "mysql:host=my_db_server.com;dbname=kida_production";
$parameters['db_user'] = "mydbuser";
$parameters['db_pass'] = "mydbpassword";
$parameters['file_db_path'] = "/some/path/to/file.db";


# this will be set up in a seperate file to define how the objects are composed
# (in symfony, these are called 'services' and this would be defined in a 'services.xml' file)
$container = array();
$container['db'] = new DB($parameters['dsn'], $parameters['db_user'], $parameters['db_pass']);
$container['fileDb'] = new SomeFileBasedDB($parameters['file_db_path']);

# the same class (UserLoader) can now load it's users from different sources without having to know about it.
$container['userLoader'] = new UserLoader($container['db']);
# or: $container['userLoader'] = new UserLoader($container['fileDb']);

# you can easily change the behaviour of your objects by wrapping them into proxy objects.
# (In symfony this is called 'decorator-pattern')
$container['userLoader'] = new SomeUserLoaderProxy($container['userLoader'], $container['db']);

# here you can choose which user-loader is used by the user-controller
$container['userController'] = new UserController($container['fileUserLoader'], $container['viewRenderer']);

ध्यान दें कि कैसे विभिन्न वर्ग एक दूसरे के बारे में नहीं जानते हैं। उनके बीच कोई प्रत्यक्ष निर्भरता नहीं है। यह कंस्ट्रक्टर में वास्तविक वर्ग की आवश्यकता नहीं के द्वारा किया जाता है, बल्कि इसके बजाय इंटरफ़ेस की आवश्यकता होती है जो इसे आवश्यक तरीके प्रदान करता है।

इस तरह आप हमेशा अपनी कक्षाओं के लिए प्रतिस्थापन लिख सकते हैं और उन्हें निर्भरता-इंजेक्शन कंटेनर में बदल सकते हैं। आपको पूरे कोडबेस की जांच करने की आवश्यकता नहीं है क्योंकि प्रतिस्थापन को केवल उसी इंटरफ़ेस को लागू करना है जो अन्य सभी वर्गों द्वारा उपयोग किया जाता है। आप जानते हैं कि सब कुछ काम करना जारी रखेगा क्योंकि पुराने वर्ग का उपयोग करने वाला प्रत्येक घटक केवल इंटरफ़ेस के बारे में जानता है और केवल इंटरफ़ेस द्वारा ज्ञात विधियों को कॉल करता है।

पीएस .:कृपया सिम्फनी प्रोजेक्ट के मेरे निरंतर संदर्भों को क्षमा करें, यह वही है जो मुझे सबसे ज्यादा उपयोग किया जाता है। अन्य प्रोजेक्ट जैसे ड्रुपल, प्रोपेल या ज़ेंड में भी शायद इस तरह की अवधारणाएँ हैं।




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. A1 को A2 के रूप में तालिका बनाएं

  2. समय अंतर खोजने के लिए MySQL समूह पंक्तियाँ

  3. MySQL डेटाबेस और टेबल साइज की जांच कैसे करें

  4. MySQL:सभी कॉलम =NULL के साथ एक पंक्ति को सम्मिलित करने से कैसे रोकें?

  5. सशर्त रूप से PHP कोड चलाएँ