如何为PDO制作单例包装?

时间:2010-04-21 15:14:40

标签: php pdo

如何制作PDO扩展的单例?扩展不起作用,因为当我尝试它时会出现致命错误...

1 个答案:

答案 0 :(得分:11)

You don't need a Singleton.

但是要回答这个问题:

您无法将公众可见度变为更严格的可见性。因此PDO不能将构造函数的可见性更改为除public之外的任何内容。所以你需要将PDO实例包装成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);
    }
}

你会这样使用它:

$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();