How can I make a singleton wrapper for PDO?

前端 未结 1 1969
悲&欢浪女
悲&欢浪女 2021-01-03 11:41

How can I make a singleton of the PDO extention? Extending doesn\'t work, because I get a fatal error when I try it ...

相关标签:
1条回答
  • 2021-01-03 12:42

    You don't need a Singleton.

    But to answer this nevertheless:

    You cannot turn a public visibility to a stricter visibility. So PDO cannot have the constructor's visibility changed to anything but public. So you need to wrap the PDO instance into a Singleton:

    class MyPdo
    {
        /**
         * @var MyPdo
         */
        protected static $_instance;
    
        /**
         * @var Pdo
         */
        protected $_pdo;
    
        /**
         * Creates instance and returns it on subsequent calls
         * 
         * @throws  InvalidArgumentException
         * @param   array $options PDO connection data
         * @returns MyPdo
         */
        public static function getInstance(array $options = NULL)
        {
            if(self::$_instance === NULL) {
    
                if($options === NULL) {
                    throw new InvalidArgumentException(
                        'You must supply connection options on first run');
                }
    
                // call constructor with given options and assign instance
                self::$_instance = new self(
                    $options['dsn'], 
                    $options['user'], 
                    $options['password'],
                    $options['driver_options']
                );
            }
    
            return self::$_instance;
        }
    
        /**
         * Creates new MyPdo wrapping a PDO instance
         * 
         * @throws PDOException
         * @param  String $dsn
         * @param  String $user
         * @param  String $password
         * @param  Array  $driver_options
         * @return void
         */
        private function __construct($dsn, $user, $password, $driver_options)
        {
            try {
                $this->_pdo = new PDO($dsn, $user, $password, $driver_options);
            } catch (PDOException $e) {
                echo 'Connection failed: ' . $e->getMessage();
            }
        }
    
        /**
         * Singletons may not be cloned
         */
        private function __clone() {}
    
        /**
         * Delegate every get to PDO instance
         *  
         * @param  String $name
         * @return Mixed
         */
        public function __get($name)
        { 
            return $this->_pdo->$name;
        }
    
        /**
         * Delegate every set to PDO instance
         *  
         * @param  String $name
         * @param  Mixed  $val
         * @return Mixed
         */    
        public function __set($name, $val)
        { 
            return $this->_pdo->$name = $val; 
        }
    
        /**
         * Delegate every method call to PDO instance
         *  
         * @param  String $method
         * @param  Array  $args
         * @return Mixed
         */    
        public function __call($method, $args) {
            return call_user_func_array(array($this->_pdo, $method), $args);
        }
    }
    

    You'd use it like this:

    $db = MyPdo::getInstance(array(
        'dsn'=>'mysql:dbname=mysql;host=127.0.0.1',
        'user' => 'root',
        'password' => 'minnymickydaisydonaldplutogoofysanfrancisco',
        'driver_options' => array(
            PDO::MYSQL_ATTR_INIT_COMMAND =>  "SET NAMES utf8"
        )));
    
    $version = $db->query( 'SELECT version();' );
    echo $version->fetchColumn();
    
    // remove reference to instance
    unset($db);
    
    // doesn't require connection data now as it returns same instance again
    $db = MyPdo::getInstance();
    $version = $db->query( 'SELECT version();' );
    echo $version->fetch();
    
    0 讨论(0)
提交回复
热议问题