【问题标题】:PDO connection class / code and class designPDO 连接类/代码和类设计
【发布时间】:2012-04-01 03:31:36
【问题描述】:

我正在尝试了解如何将 PDO 与“连接”类一起使用。

class db { 

    private static $dbh; 

    private function __construct(){}
    private function __clone(){} 

    public static function connect() { 
        if(!self::$dbh){ 
            self::$dbh = new PDO("mysql:host=localhost;dbname=database", "user", "password");
            self::$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 
        } 
        return self::$dbh; 
    } 

    final public static function __callStatic( $chrMethod, $arrArguments ) {   
        $dbh = self::connect(); 
        return call_user_func_array(array($dbh, $chrMethod), $arrArguments);  
    }
} 

我从http://php.net/manual/en/book.pdo.php 获取了上述内容,并稍微修改了变量,但我想知道如何在这个 db 类中连接到 PDO 连接对象?

$dbh = new db; //intiate connection???

$stmt = $dbh->prepare("SELECT * FROM questions WHERE id = :id"); // or should I do db::prepare.. ???
$stmt->bindParam(':id', $_GET['testid'], PDO::PARAM_INT);

if ($stmt->execute()) {
    while ($row = $stmt->fetch()){
        print_r($row);
    }
}

有什么想法吗?谢谢

【问题讨论】:

  • 我不是想理解你为什么在这里使用全局静态类方法。

标签: php mysql oop pdo class-design


【解决方案1】:

据我了解,您希望有一个“连接类”,它为 PDO 实例实现延迟加载。然后您希望代码中的对象能够从代码中的每个位置访问该连接,从而有效地创建一个单例。

别这样。

您正在清除应用程序中的全局状态,并且所有启用 DB 的类都与连接类的 NAME 紧密耦合。

我会推荐一些不同的方法。正如@Steven 所暗示的,您应该使用工厂来创建需要数据库连接的对象。

这是一个简化的实现。

class DataMapperFactory
{
    protected $provider = null;
    protected $connection = null;

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

    public function create( $name)
    {
        if ( $this->connection === null )
        {
            $this->connection = call_user_func( $this->provider );
        }
        return new $name( $this->connection );
    }

}

你会像这样使用它:

$provider = function()
{
    $instance = new PDO('mysql:......');
    $instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $instance->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
    return $instance;
};

$factory = new DataMapperFactory( $provider );

现在每次执行$factory->create('SomeClass') 时,它都会创建该类的一个新实例,并在构造函数中为其提供正确的数据库连接。而且,第一次执行时,它会打开与数据库的连接。

【讨论】:

    【解决方案2】:

    这或多或少是我的做法。我不确定这是否是最好的方法,但它对我有用。

    我的工厂类是我的代码的核心。从这里我生成我使用的所有类。我的工厂类保存在单独的文件factory.class.php

    通过拥有一个工厂类,我只需要包含一次类文件。如果我没有这个,我将不得不为每个必须使用它的文件包含我的类文件。如果以后需要更新类文件名,只需要在工厂类文件中进行更新即可。

    创建工厂对象的另一个原因是减少数据库连接数。

    我将每个类保存为单独的文件

    工厂类

    include_once('person.class.php');
    include_once('tracking.class.php');
    include_once('costAnalyzis.class.php');
    include_once('activity.class.php');
    
    class Factory {
      function new_person_obj($id = NULL) { return new Person(Conn::get_conn(), $id); }  
      function new_tracking_obj($id = NULL) { return new Tracking(Conn::get_conn(), $id); }
      function new_costAnalyzis_obj() { return new CostAnalyzis(Conn::get_conn()); }
      function new_activity_obj() { return new Activity(Conn::get_conn()); }
    }    
    

    连接类

    // I have this class in the same file as Factory class
    // This creates DB connection and returns any error messages
    class Conn {
      private static $conn = NULL;
    
      private function __construct() {}
    
      private static function init() {
          $conf = self::config();
          try { 
            self::$conn = new PDO($conf['dsn'], $conf['user'], $conf['pass'], array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
          } 
          catch (PDOException $e) {
            // We remove the username if we get [1045] Access denied
            if (preg_match("/\b1045\b/i", $e->getMessage())) 
              echo "SQLSTATE[28000] [1045] Access denied for user 'name removed' @ 'localhost' (using password: YES)";
            else
              echo $e->getMessage();  
          }
      }
    
      public static function get_conn() {
        if (!self::$conn) { self::init(); }
        return self::$conn;
      }
    
      // I used to get login info from config file. Now I use Wordpress constants
      private static function config() {
        $conf = array();
    
        $conf['user']    = DB_USER; //$config['db_user'];
        $conf['pass']    = DB_PASSWORD; //$config['db_password'];
        $conf['dsn']     = 'mysql:dbname='.DB_NAME.';host='.DB_HOST;
    
        return $conf;
      }  
    }
    

    不同的类对象

    这些是你的课程。这是您处理数据的地方 在我自己的代码中,我使用三层架构,将表示层与业务层和数据对象层分开。

    class Person extends PersonDAO {
    
      function getPersonData($id) {
        $result = parent::getPersonData($id);
    
        // Here you can work with your data. If you do not need to handle data, just return result
        return $result;
      }
    }
    
    
    // I only have SQL queries in this class and I only return RAW results.
    class PersonDAO {
    
      // This variable is also available from you mother class Person 
      private $db;
    
        // Constructor. It is automatically fired when calling the function.
        // It must have the same name as the class - unless you define 
        // the constructor in your mother class.
        // The &$db variable is the connection passed from the Factory class.
        function PersonDAO (&$db) {
          $this->db = &$db;
        }
    
    
      public function get_data($id) {
         $sql ="SELECT a, b, c
              FROM my_table
              WHERE id = :id";
    
         $stmt = $this->db->prepare($sql);
         $stmt->execute(array(':id'=> $id));
         $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
    
         return $result;
      }
    
      public function get_some_other_data() {
        $sql ="SELECT a, b, c
              FROM my_table_b";
    
        $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
    
        return $result;      
      }
    }
    

    对你的其他课程做同样的事情。

    把它们放在一起

    请注意,我们只包含一个文件,即工厂文件。所有其他类文件都包含在 Factory 类文件中。

    // Include factory file
    include_once('factory.class.php');
    
    //Create your factory object
    $person = Factory::new_person_obj();
    
    //Get person data
    $data = $person->getPersonData('12');
    
    // output data
    print_r($data);
    

    【讨论】:

    • 非常感谢史蒂文的回复。我收到“在...中的非对象上调用成员函数 new_obj()”我已经更新了 sql 查询和数据库信息...您能否简要评论每个部分的作用?抱歉,我是 OOP 的新手..!
    • 我也没有使用 WP.. 但无论如何都定义了这些变量。另外如何添加新查询?非常感谢:)
    • 我已将代码更新为与我自己的代码结构相似。测试并看看这是否有效。如果你也理解我在这里使用的逻辑,它会有所帮助。
    • 当您将一个对象传递给另一个对象时,您不必使用引用。不是从 PHP5 开始。此外,由于 PHP5 的构造函数是 __construct() 方法。这两点都使function PersonDAO (&$db) 行变得非常糟糕(它仍然可以工作,但这是一种非常糟糕的做法)。
    • 关于准备好的陈述的另一个说明。如果在绑定参数时没有设置自定义PDO::PARAM_类型,值会被绑定为字符串。
    猜你喜欢
    • 1970-01-01
    • 2016-01-09
    • 1970-01-01
    • 2015-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多