如何为 PDO 制作单例包装?

发布于 2024-08-29 16:43:19 字数 49 浏览 3 评论 0原文

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

淡淡離愁欲言轉身 2024-09-05 16:43:19

你不需要单例。

但是要回答尽管如此:

你不能将公众可见性转变为更严格的可见性。因此,PDO 不能将构造函数的可见性更改为除公共之外的任何内容。因此,您需要将 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();

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();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文