Php 如何在其他类中使用PDO连接?

Php 如何在其他类中使用PDO连接?,php,oop,pdo,Php,Oop,Pdo,我想我在理解OOP是如何工作的方面有问题。我已经改变了代码,但这不是我认为的支持方式。下面的场景(不,我不是自己创建用户登录,它实际上只是为了让本地开发人员更好地理解OOP): 我有一个database.php文件: class Database { /* Properties */ private $conn; private $dsn = 'mysql:dbname=test;host=127.0.0.1'; private $user = 'root';

我想我在理解OOP是如何工作的方面有问题。我已经改变了代码,但这不是我认为的支持方式。下面的场景(不,我不是自己创建用户登录,它实际上只是为了让本地开发人员更好地理解OOP):

我有一个database.php文件:

class Database {

    /* Properties */
    private $conn;
    private $dsn = 'mysql:dbname=test;host=127.0.0.1';
    private $user = 'root';
    private $password = '';

    /* Creates database connection */
    public function __construct() {
        try {
            $this->conn = new PDO($this->dsn, $this->user, $this->password);
        } catch (PDOException $e) {
            print "Error!: " . $e->getMessage() . "";
            die();
        }
        return $this->conn;
    }
}
所以在这个类中,我创建了一个数据库连接并返回了连接(object?)

然后我有第二个类,著名的用户类(实际上我没有使用autoload,但我知道):

这就是我的两门课。你看,没什么大不了的。现在,不要对函数名
login
感到困惑-实际上,我只是尝试从数据库中选择一些用户名和用户名并显示它们。我试图通过以下方式实现这一目标:

$user = new User();
$list = $user->login();

foreach($list as $test) {
    echo $test["username"];
}
问题来了。执行此代码时,我会收到以下错误消息:

未捕获错误:调用未定义的方法数据库::prepare()

我不确定我是否真的理解是什么导致了这个错误

当我更改以下内容时,代码运行良好:

将database.php中的
$conn
更改为public而不是private(我认为这很糟糕…?但是当它是private时,我只能在database类内部执行查询,我是对的?那么我应该将所有这些查询都放在database类中吗?我认为这很糟糕,因为在一个大项目中它会变得非常大..)

我要做的第二个改变是: 在user.php文件中将
$this->conn->prepare
更改为
$this->conn->conn->prepare
。在这里我真的不知道为什么

我的意思是,在
user.php
的构造函数中,我有一个
$this->conn=new Database()
,由于新数据库将从DB类返回连接对象,我真的不知道为什么必须有第二个
conn->
  • 你现在的课很没用。如果数据库包装器为PDO添加了一些额外的功能,那么创建数据库包装器是有意义的。但是考虑到它当前的代码,最好使用香草PDO
  • 无论哪种方式,都可以从vanilla PDO或数据库类创建一个单个$db实例
  • 将其作为构造函数参数传递给每个需要数据库连接的类
database.php:

<?php
$host = '127.0.0.1';
$db   = 'test';
$user = 'root';
$pass = '';
$charset = 'utf8';

$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$opt = [
    \PDO::ATTR_ERRMODE            => \PDO::ERRMODE_EXCEPTION,
    \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
    \PDO::ATTR_EMULATE_PREPARES   => false,
];
$pdo = new \PDO($dsn, $user, $pass, $opt);
输出:

username_foo
username_bar
username_baz

查看my以了解更多PDO详细信息。

构造函数不应返回任何内容:-要访问该方法,您的
数据库
类需要扩展
PDO
您的错误是
$this->conn->prepare(
您试图在数据库类上调用prepare函数,但没有prepare函数。您可以将数据库的
$conn
设置为公共,这将导致
$this->conn->conn->prepare
。数据库的返回值
\u构造()
返回的是数据库对象而不是连接,即使您
重新运行$this->conn
也没错,因为在
数据库中
conn
PDO
实例,并且具有这样的属性capabilities@Twinfriends是的,我确定..如果您将登录名放入数据库类,
$this->conn
是PDO对象对于Database,不是Database对象本身,而是要调用的Database类中的Database对象
$this->conn
-在这种情况下,这是一个PDO实例,因此该方法存在,您很好。但是,当您从外部实例化
Database
时,您正在创建一个新的
Database
对象,它只包含您定义的方法-除非您扩展了另一个类。虽然这是一个很好的解决方法,但我个人不喜欢在我的模型中有这种连接。最好保持它“干净”扩展包含连接方法的基础模型。@Niekvandmaaden如果扩展基础模型,那么子类中也有连接。没错,但我的意思是子模型将是“干净的”从可读性的角度来看,它不会被额外的方法和变量阻塞。不管怎样,模型中唯一不包含它们的方法是使用静态数据库类,但这不是正确的方法。@NiekvanderMaaden如果你想让类保持干净,请查找数据映射器模式。如果我有3个对象共享在相同的迭代中使用相同的db连接是件坏事吗?
<?php
class User {
    /* Properties */
    private $conn;

    /* Get database access */
    public function __construct(\PDO $pdo) {
        $this->conn = $pdo;
    }

    /* List all users */
    public function getUsers() {
        return $this->conn->query("SELECT username, usermail FROM user")->fetchAll();
    }
}
include 'database.php';
$user = new User($pdo);
$list = $user->getUsers();

foreach($list as $test) {
    echo $test["username"],"\n";
}
username_foo
username_bar
username_baz