【问题标题】:PHP - How to access pdo object from other (multiple) classesPHP - 如何从其他(多个)类访问 pdo 对象
【发布时间】:2013-08-08 04:30:14
【问题描述】:

我正在切换我的 MVC 以使用 PDO(我知道,过期了)。我的应用程序过去使用过以下类层次结构:

Database.class>Main.class>User.class

(彼此延伸)。但在创建任何对象之前,mysql 连接已建立(mysql_connect)。一旦连接打开,我就可以使用 Database.class 作为包装类,通过它执行我的所有查询。通过扩展,User.class 中的查询可以简单地通过调用“查询”函数($this->query)来进行。

使用 PDO,我尝试模仿该过程但发现错误。我在 Database.class 中创建了一个单例函数:

function __construct()
{
    $this->db = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8', DB_USER, DB_PASSWORD);
    $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $this->db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
}

public static function getInstance()
{
    if (!isset(self::$instance)){
        $object = __CLASS__;
        self::$instance = new $object;
    }
    return self::$instance;
}

function query($qry,$params=NULL){
    $qry = $this->db->prepare('SELECT * FROM users WHERE userID = :userID');
    $qry->execute(array(':userID' => 1));
    $results = $qry->fetchAll(PDO::FETCH_ASSOC);
    return $results;
}

然后在 Main.class 我得到实例:

function __construct()
{
    $this->db = parent::getInstance();
}

所以在 User.class 我尝试调用

function __construct(){
    parent::__construct();
}
function test(){
    return $this->db->query("test");
}

所以我可以从 Main.class 对象运行任何查询。但是,如果我尝试从 User.class 对象运行查询,则会收到错误消息:“调用非对象上的成员函数 query()”换句话说,如果 User.class 扩展 main 我应该能够访问该变量$db in Main from User.class(我在创建 User 对象时调用 Main 的构造函数)。部分问题是 Main.class 在应用程序的早期创建为它自己的对象,我相信会导致创建两个 PDO 实例 - 这就是为什么它不能通过扩展工作(通过第二个对象也扩展数据库.class)

所以我的问题是:有没有办法做到这一点?或者我最好的选择是对我创建的每个对象使用注入(因为一些脚本包含多个扩展 Main.class 的对象 - 每次都尝试创建 PDO 的实例)并将 pdo 对象传递给构造函数?我宁愿不必这样做(标记越少越好)所以另一种选择是使用所有类都使用的 STATIC 变量?最好的方法是什么? (让我知道这是否令人困惑)

我见过有人为此使用注入,也见过扩展 pdo 包装类的示例(但只有一次)。

谢谢! (我喜欢堆栈溢出!)

【问题讨论】:

标签: php class pdo code-injection extend


【解决方案1】:

您不希望其中任何一个扩展数据库类,因为这实际上会使它们全部成为您只能拥有一个实例的单例...您想让它们改为使用数据库类。因此,您会将最抽象的数据库方法放在Database 上,然后为特定事物创建查询的方法将放在User 上或您有什么。这意味着您的 Database 实际上包装了 PDO 并且是所有其他类用于 db 操作的内容。 MainBase 类可能甚至不需要,除非您尝试实现活动记录或其他东西。

class Database {
   static protected $instance;

   /**
    * @var PDO
    */
   protected $connection;

   protected function __construct($dsn, $user, $pass, $attrs = array()) {
       // create pdo instance and assign to $this->pdo
   }

   public static function getInstance() {
       if(!self::$instance) {
           // get the arguments to the constructor from configuration somewhere
           self::$instance = new self($dsn, $user, $pass);
       }

       return self::$instance;
   }

   // proxy calls to non-existant methods on this class to PDO instance
   public function __call($method, $args) {
       $callable = array($this->pdo, $method);
       if(is_callable($callable)) {
           return call_user_func_array($callable, $args);
       }
   }
}

class Main {
   protected $db;

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

    class User extends Main{

       public function __construct() {
            parent::__construct();
       }

       public function findById($id) {
           $qry = $this->db->prepare('SELECT * FROM users WHERE userID = :userID');
           $qry->execute(array(':userID' => $id));
           $results = $qry->fetchAll(PDO::FETCH_ASSOC);

           return $results
       }
    }

【讨论】:

  • 感谢您的意见。 Main 类还有几个其他函数,它们在整个应用程序中使用。我的大部分课程都扩展了 Main。所以基本上一个扩展另一个具有单例方法的类的类也变成了单例对象?你建议我使用注射吗?
  • 我总是建议在单例上注入 :-) 如果你有一个单例,那么整个层次结构将有一个“实例”,这就是单例通常的工作方式。你不能在类之间有不同的构造函数签名......
猜你喜欢
  • 2018-09-09
  • 1970-01-01
  • 1970-01-01
  • 2012-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-06
  • 1970-01-01
相关资源
最近更新 更多