PHP-如何从其他(多个)类访问pdo对象

PHP-如何从其他(多个)类访问pdo对象,php,class,pdo,code-injection,extend,Php,Class,Pdo,Code Injection,Extend,我正在将MVC转换为使用PDO(我知道,过期了)。我的应用程序过去使用过以下类层次结构: Database.class>Main.class>User.class (一个接一个)。但是在创建任何对象之前,已经建立了mysql连接(mysql\u connect)。一旦连接打开,我就可以使用Database.class作为包装类来执行所有查询。通过扩展,只要调用“query”函数($this->query),就可以在User.class中进行查询 使用PDO,我试图模拟这个过程,但发现了错误。我在

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

Database.class>Main.class>User.class

(一个接一个)。但是在创建任何对象之前,已经建立了mysql连接(mysql\u connect)。一旦连接打开,我就可以使用Database.class作为包装类来执行所有查询。通过扩展,只要调用“query”函数($this->query),就可以在User.class中进行查询

使用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,我应该能够从User.class访问main中的变量$db(在创建用户对象时,我调用main的构造函数)。问题的一部分在于Main.class是在应用程序的早期创建的,作为它自己的对象,我认为这会导致创建两个PDO实例——这就是为什么它不能通过扩展(通过另一个也扩展database.class的对象)工作的原因

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

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


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

您不希望其中任何一个扩展数据库类,因为这实际上会使它们都是单例,您只能有一个实例。。。您希望让他们改用数据库类。因此,您可以将最抽象的db方法放在
数据库上,然后为特定内容创建查询的方法放在
用户上。这意味着您的
数据库
实际上包装了
PDO
,这是所有其他类用于数据库操作的工具。
Main
Base
类甚至可能不需要,除非您试图实现活动记录或其他功能

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
       }
    }

这篇文章可能会有所帮助:另外:谢谢你的投入。主类还具有几个其他函数,这些函数在整个应用程序中使用。我的大部分课程都扩展了主课程。所以基本上,一个扩展了另一个具有单例方法的类的类也变成了单例对象?你建议我使用注入吗?我总是建议注入而不是单例:-)如果你有单例,那么整个层次结构将有一个单一的“实例”,这就是单例通常的工作方式。在不同的类中不能有不同的构造函数签名。。。