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

How to use PDO connection in other classes?

提问人:Twinfriends 提问时间:4/26/2017 最后编辑:yiviTwinfriends 更新时间:11/29/2022 访问量:20171

问:

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

我有一个数据库.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;
    }
}

因此,在本类中,我正在创建一个数据库连接,并返回该连接(对象?

然后我还有第二个类,著名的 User 类(实际上我没有使用自动加载,但我知道它):

include "database.php";

class User {
    /* Properties */
    private $conn;

    /* Get database access */
    public function __construct() {
        $this->conn = new Database();
    }

    /* Login a user */
    public function login() {
        $stmt = $this->conn->prepare("SELECT username, usermail FROM user");
        if($stmt->execute()) {
            while($rows = $stmt->fetch()) {
                $fetch[] = $rows;
            }
            return $fetch;
        }
        else {
            return false;
        }
    }
}

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

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

foreach($list as $test) {
    echo $test["username"];
}

问题来了。当我执行此代码时,我收到以下错误消息:

未捕获的错误:调用未定义的方法 Database::p repare()

而且我不确定我是否真的理解导致此错误的原因。

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

将数据库 .php 更改为公共而不是私有(我认为这很糟糕......?但是当它是私有的时,我只能在 Database 类内执行查询,对吗?那么我应该把所有这些查询都放在 Database 类中吗?我认为这很糟糕,因为在一个大项目中,它会变得非常大。$conn

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

我的意思是,在 I 有一个的构造函数中,由于 new Database 将从 DB 类返回连接对象,我真的不知道为什么必须有第二个user.php$this->conn = new Database()conn->

php 哎呀 pdo

评论

1赞 CD001 4/26/2017
构造函数不应返回任何内容: stackoverflow.com/questions/6849572/... - 要访问该方法,您的类需要扩展DatabasePDO
2赞 Nitro.de 4/26/2017
您的错误是您正在尝试调用 Database 类的 prepare 函数,但没有 prepare 函数。您可以将 of 数据库设为公共数据库,这将导致 .数据库的返回值返回的是数据库对象,而不是连接,即使您$this->conn->prepare($conn$this->conn->conn->prepare__construct()retrun $this->conn
1赞 xmike 4/26/2017
没错,因为在你的类中是实例并且具有这样的功能DatabaseconnPDO
1赞 Nitro.de 4/26/2017
@Twinfriends是的,我敢肯定......如果将 Login 放入 Database 类中,则 Database 的 PDO 对象,而不是 Database 对象本身$this->conn
1赞 CD001 4/26/2017
在您将调用的数据库类中 - 在这种情况下,这是一个 PDO 实例,因此该方法存在并且您很好。但是,当您从外部实例化时,您将创建一个新对象,该对象仅具有您定义的方法 - 除非您扩展另一个类。$this->connDatabaseDatabase

答:

23赞 Your Common Sense 4/26/2017 #1
  • 不要创建像你的类这样的类,因为它相当无用。如果数据库包装器向 PDO 添加一些额外的功能,那么创建数据库包装器将是有意义的。但鉴于其当前的代码,最好使用普通的 PDO。Database
  • 从 vanilla PDO 或数据库类创建单个 $db 实例。
  • 将其作为构造函数参数传递到需要数据库连接的每个类中

数据库:.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);

用户.php

<?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();
    }
}

应用:.php

include 'database.php';
$user = new User($pdo);
$list = $user->getUsers();

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

输出:

username_foo
username_bar
username_baz

查看我的(唯一合适的)PDO教程,了解更多PDO详细信息。

评论

1赞 Niek van der Maaden 4/26/2017
虽然这是解决它的好方法,但我个人不喜欢在我的模型中建立联系。不妨保持“干净”,扩展包含连接方法的基本模型。
0赞 Your Common Sense 4/26/2017
@NiekvanderMaaden,如果扩展了 Base 模型,那么在 offspring 类中也有连接。
0赞 Niek van der Maaden 4/26/2017
没错,但我的意思是你的子模型在可读性方面将是“干净的”,它不会被额外的方法和变量堵塞。不管怎样,在模型中不让它们的唯一真正方法是使用静态数据库类,但这不是正确的方法。
1赞 Your Common Sense 4/26/2017
@NiekvanderMaaden,如果您希望您的类是干净的,请查找 Data Mapper 模式。
0赞 Botea Florin 11/24/2018
如果我有 3 个对象在同一迭代中共享相同的数据库连接,这是一件坏事吗?