【问题标题】:PHP PDO injection inside a class类中的 PHP PDO 注入
【发布时间】:2018-06-01 10:12:10
【问题描述】:

我正在尝试了解如何在课程中使用PDO。我写了这个简单的类,它拥有一个PDO 连接,它作为__construct() 的一部分在另一个类中传递。问题是每次我尝试使用需要数据库连接的类的方法时,我都会收到一条与PDO 的内置函数相关的错误消息,如prepare()execute()。错误是PHP Fatal error: Uncaught Error: Call to undefined method Database::prepare()。我该如何解决这个问题?我已经阅读了有关依赖注入的内容,但现在在使用 PDO 时如何将这种模式应用于代码有点令人困惑@

<?php

class Database {

    public function __construct() {

        return $this->db = new PDO("mysql:host=localhost;dbname=testdb;", "root", "root");
    }

}

class user {

    public function __construct($db) {

        $this->db = $db;
    }

    public function createUser($email, $username, $password) {

        $stmt = $this->db->prepare("INSERT INTO users (email,username,password) VALUES (?, ?, ? )");
        if ($stmt->execute(array($email, $username, $password))) {
            echo "Account successful created";
        } else {
            echo "Something was wrong during the registration process.";
        }
    }

    public function loginUser($username, $password) {

        $stmt = $this->db->prepare("SELECT email,username,password FROM users WHERE email = ? OR username = ?");

        $stmt->execute(array($username, $username));
        if ($stmt->rowCount() > 0) {
            $result = $stmt->fetch(PDO::FETCH_OBJ);
            if (password_verify($password, $result->password)) {
                echo "logged";
            } else {
                echo "wrong password";
            }
        } else {
            echo "Username or email does not exist in the database.";
        }
    }

}

【问题讨论】:

  • 修复引号以正确突出显示。
  • 修复这一行 return $this->db = new PDO('mysql:host=localhost;dbname=testdb;','root','root');
  • 引用已修复,对错字表示抱歉!
  • 你是通过Database 的实例向User 传递,而不是PDO 的实例。在Database 中为您的数据库处理程序创建一个getter/setter,例如getConnection(),然后您可以执行$this-&gt;db-&gt;getConnection()-&gt;prepare,或者只是摆脱封装并将PDO 的实例传递给User
  • @DarkBee 你能举个例子吗?

标签: php pdo


【解决方案1】:

如果您想将PDO 连接封装在一个额外的类中,您应该为实际连接创建一个getter

<?php 
    class Database {
        private $dbh = null;

        public function __construct($user, $pass, $database) {
            $this->dbh = new PDO("mysql:host=localhost;dbname=".$database.";", $user, $pass);
        }

        public function getConnection() {
            return $this->dbh;
        }
    }

    class User {
        private $db = null;

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

        public function createUser($email, $username, $password) {
            $stmt = $this->db->getConnection()->prepare("INSERT INTO users (email,username,password) VALUES (?, ?, ? )");
            if ($stmt->execute(array($email, $username, $password))) {
                echo "Account successful created";
            }else {
                echo "Something was wrong during the registration process.";
            }
        }       
    }

}

$user = new User(new Database('root', 'root', 'testdb'));

来自cmets:

最好将PDO 的实例传递给您的类。这应该有效:

<?php
class user {
    public function __construct(\PDO $db) {
        $this->db = $db;
    }
}

<?php
    /** Init the one and only DB connection for this request **/
   $dbh = new PDO("mysql:host=localhost;dbname=".$database.";", $user, $pass);

   //... Do some stuff
   //....
   $user = new User($dbh);

【讨论】:

  • 我已经测试过代码并且工作顺利。是否也可以通过某种方式避免getConnection()
  • 当我开始编写这段代码时,我正在使用User 类,方法是在__construct(PDO $db) 这样的结构中添加PDO 依赖项。
  • 是什么让你决定放弃这种做法?如果除了存储处理程序之外,您不打算向 Database 类添加更多登录信息,您应该像之前一样传递 PDO 实例
  • 如果你想避免 getConnection() 部分,这意味着你要么需要在 Database 类中链接每个 PDO 方法,要么让 DatabasePDO 扩展,但是然后你回到你的起点
  • @user9741470 您的第一种方法更加明确。你知道你正在处理什么对象和方法。如果我查看上面的用户类,我不知道数据库对象是什么。
猜你喜欢
  • 2017-02-13
  • 2011-04-12
  • 2015-09-14
  • 1970-01-01
  • 2017-12-09
  • 1970-01-01
  • 2018-06-13
  • 2014-03-30
相关资源
最近更新 更多