How to connect to MySQL only once, without ever having to instantiate?

6

How do I connect to MySQL only once, without having to re-write it in every function?

Currently I do this:

class Site {
    var $driver;
    var $host;
    var $dbname;
    var $user;
    var $pass;

    public function __construct($driver, $host, $dbname, $user, $pass) {
        $this->driver = $driver;
        $this->host = $host;
        $this->dbname = $dbname;
        $this->user = $user;
        $this->pass = $pass;        
    }
    public function jazz() {
        $d = new PDO("$this->driver:host=$this->host;dbname=$this->dbname", "$this->user","$this->pass");
        $d->query('SELECT name, price FROM products ORDER BY id ASC');
    }
    public function buzz() {
        $c = new PDO("$this->driver:host=$this->host;dbname=$this->dbname", "$this->user","$this->pass");
        $c->query('SELECT name, age FROM clients ORDER BY name ASC');
    }
}
    
asked by anonymous 08.12.2014 / 14:51

3 answers

6

The ideal would be to break this code into two classes one only for the connection of the bank (if it changes the change would only be in one place) and another to the site, in the latter the constructor would receive the connection instead of user, password , bank etc.

The keyword var was used in php4 to define various class members in php5 use the access modifiers:

  • private These members can only be accessed by the class.
  • protected These members are visible in objects and in decent ones (inheritance).
  • Public Anyone can have these attributes.
class Site {
    private $db;

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

    public function jazz() {
        return $this->db->query('SELECT name, price FROM products ORDER BY id ASC');
    }

    public function buzz() {
        return $this->db->query('SELECT name, age FROM clients ORDER BY name ASC');
    }
}
    
08.12.2014 / 15:09
5

There are two possibilities for solving this problem, one of which is less appropriate from the point of view of Object Orientation but perhaps more useful for your particular case.

The properties of a class are used to store everything that the class, through its object, may need during the request in which it was instantiated.

If you have several methods that act as wrappers for the repeating part of the PDO and all of them use the same object, instead of opening a connection for each method, you store the instance of the PDO in a class, like this:

class Site {

    private $conn;

    public function __construct($driver, $host, $dbname, $user, $pass) {
        $this -> conn = new PDO( /** ... */ );
    }

    public function jazz() {
        return $this -> conn -> query( /** ... */ );
    }
}

The second alternative is a bit more complex, but much more timely from the point of view of Object Orientation because, in the ideal scenario, you should not restrict access to your data to just one database, much less force the use of the PDO.

In such cases, using a Design Pattern called Registry you have an Object Oriented implementation of basically a large box , where you can save whatever you want to use later:

class Registry {

    private $registry = array();

    /**
     * Add/Set a Registry Entry value
     *
     * @param string $key
     *  Registry Key
     *
     * @param mixed $value
     *  Value to be stored
     *
     * @return Registry
     *  Registry Object (Fluent Interface)
     */
    public function set( $key, $value ) {

        $key = trim( $key );

        if( ! empty( $key ) ) {

            $this -> registry[ $key ] = $value;
        }

        return $this;
    }

    /**
     * Get a Registry Entry value
     *
     * @param string $key
     *  Registry Key
     *
     * @return mixed
     *  Registry Entry
     */
    public function get( $key ) {

        $key   = trim( $key );

        return ( array_key_exists( $key, $this -> registry ) ? $this -> registry[ $key ] : FALSE );
    }
}

However, by itself, the Registry does not solve the problem of the state of the object, which is precisely what concerns its problem.

Without solving this problem, you would see:

  • Duplicating code, as it currently should be doing
  • Create a global variable and access it in the local scope of methods used by the global keyword or the superglobal array $ GLOBALS , which is extremely wrong

To solve this "problem" of the Registry, since it is not exactly a problem it does not solve that it was not designed to solve, just integrate it to the other Design Pattern, the Singleton .

Singleton is a standard that aims to make the instance of a single object unique. No matter where in the code you invoke the object, it will always be the same, even with the same properties populated in the previous "levels."

  

With levels I mean the ver- ical and increasing flow of the Application. The lowest levels would be first-instance files, such as index.php or in more elaborate systems a FronController and higher levels, Action / Page Controllers or Models.

Singleton is a very useful standard if used the right way.

Unrestrained use of this pattern in the past has given it a bad reputation among experienced programmers because when you abuse Singleton, you simply leave global variables "cute".

But allied to the Registry, creating what we call Singleton Registry, you have a large box accessible at any scope to store everything that needs to be used in any part of the code.

Let's see how it goes:

/**
 * Registry Class
 *
 * @author        Bruno Augusto
 *
 * @copyright     Copyright (c) 2010 Next Studios
 * @license       http://creativecommons.org/licenses/by/3.0/   Attribution 3.0 Unported
 */
class Registry {

    /**
     * Registry Instance
     *
     * @staticvar Registry $_instance
     */
    private static $_instance;

    /**
     * Registry Storage
     *
     * @var array $registry
     */
    private $registry = array();

    /**
     * Enforcing Singleton. Disallow Cloning
     */
    private function __clone() {}

    /**
     * Enforcing Singleton. Disallow Direct Constructor
     */
    private function __construct() {}

    /**
     * Get Registry Instance
     *
     * @return Registry
     *  Registry Instance
     */
    public static function getInstance() {

        if( NULL === self::$_instance ) {

            self::$_instance = new Registry;
        }

        return self::$_instance;
    }

    /**
     * Add/Set a Registry Entry value
     *
     * @param string $key
     *  Registry Key
     *
     * @param mixed $value
     *  Value to be stored
     *
     * @return Next\Components\Registry
     *  Registry Object (Fluent Interface)
     */
    public function set( $key, $value ) {

        $key = trim( $key );

        if( ! empty( $key ) ) {

            $this -> registry[ $key ] = $value;
        }

        return $this;
    }

    /**
     * Get a Registry Entry value
     *
     * @param string $key
     *  Registry Key
     *
     * @return mixed
     *  Registry Entry
     */
    public function get( $key ) {

        $key   = trim( $key );

        return ( array_key_exists( $key, $this -> registry ) ? $this -> registry[ $key ] : FALSE );
    }
}

Did you notice the difference?

We block access to the object constructor, so it can not be instantiated with the new operator, which is what makes the instance of the object change.

  

Extra Credit: To see a representation of the instance variation of an object, pass the instance as an argument to spl_object_hash ()

But to work with objects you need to instantiate it and you will instantiate the Registry class, but indirectly through the static Registry :: getInstance () method.

This method queries a static property and checks to see if there is an instance of the object stored in it. If it does not exist, it means that the Registry is being used for the first time, so it is created.

At other times, at higher levels, this instance already exists and instead of being created again, it is returned the way it is.

And with "whatever it is," I mean with everything inside that big box, in your case, your connection object, which you point to through Registry :: set () and rescues through Registry :: get () . Let's see?

$link = new Site( /** ... */ );
Registry::getInstance() -> set( 'link', $link );

// Em alguma outra parte do código DEPOIS de adicionar o objeto à caixa

$link = Registry::get( 'link' );

$link -> prepare( '/** ... */' );

// ...

: D

    
08.12.2014 / 15:13
4

For this to happen you would need to return the PDO object created directly by the class, try something like:

class DB{
    private static $conn = null;
    private static $tns = "Connection String";
    private static $db_username = '<USERNAME>';
    private static $db_password = '<SENHA>';

    private function __construct(){

    }

    public static function conn(){
        if(is_null(self::$conn)){
            try{
                self::$conn = new PDO("oci:dbname=".self::$tns,self::$db_username,self::$db_password);
            } catch(PDOException $e){
                self::$conn = die($e->getMessage());
            }
        }

        return self::$conn;
    }

    public function __destruct(){
        self::$conn = null;
    }
}

Note that in the conn () method, it checks whether the object is null or not, if it is not null, that there is already a connection instantiated by the static class, so it returns the object itself, without instantiate a new class.

    
08.12.2014 / 15:10