【问题标题】:PHP OOP and PDOPHP OOP 和 PDO
【发布时间】:2012-01-28 20:20:18
【问题描述】:

我第一次真正尝试广泛使用 PHP OOP 和 PDO。我终于让脚本工作了,但正如你注意到的那样,为了做到这一点,我必须将 PDO 连接移动到登录函数中——最初它只是在 __construct() 中。我不想打开一个新的 PDO 连接,这很草率。如何在全班保持相同的连接?

 <?php
class user{

public $id;
public $name;
public $email;
private $password;

public function __construct() {
    $DBH = new PDO("mysql:host=HOST;dbname=DB", "USER", "PASS");  
    $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}

public function login($email,$password,$type){

    $DBH = new PDO("mysql:host=HOST;dbname=DB", "USER", "PASS");  
    $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $password_hash = sha1($password);
    try{
        if ($type != "actives") {
            throw new Exception("Type Handling Error");
        }
        $STH = $DBH->query("SELECT id, email, password FROM $type WHERE email='$email' AND password='$password_hash'");
        $STH->setFetchMode(PDO::FETCH_ASSOC);  
        $row_count = $STH->rowCount();  
        $row = $STH->fetch();

        if($row_count == 1){
            session_start();
            session_regenerate_id();
            $_SESSION['id'] == $row[id];
            return true;
        }
        else{
        return false;
        }
    }
    catch (Exception $e) {
        echo $e->getMessage();
    }

}

public function loggout(){
    session_destroy();
    setcookie(session_name(), session_id(), 1, '/');
}

【问题讨论】:

  • Google 搜索 dependancy injection(恕我直言的最佳实践)或 singleton 模式(最容易实现,但更难编写测试)。

标签: php oop


【解决方案1】:

使数据库处理类中的私有成员:

class user
{    
    public $id;
    public $name;
    public $email;
    private $password;
    private $dbh;

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

    public function login($email, $password, $type)
    {
        $dbh = $this->dbh;
        ...
    }

用法:

$pdo = new PDO("mysql:host=HOST;dbname=DB", "USER", "PASS");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$user = new User($pdo);

【讨论】:

  • 更好的是,在外部实例化它并将 PDO 对象传递给变量。 public function __construct($dbh) { $this-&gt;dbh = $dbh; }
  • @Ryan,真相以正确的方式做到这一点是绝对正确的。作为(不太普遍接受的)替代方案,我经常将我的 PDO 对象放在$GLOBALS 中,因此我不必将它传递给使用它的各种类。这违背了一些 OOP 原则,但确实有效。我不确定我会推荐它,但这是可能的。
  • 我尝试了你的建议。这是有道理的。但由于某种原因,它不起作用。我收到:致命错误:在第 21 行的 /home/X/X/classes/user.php 中的非对象上调用成员函数 query()
【解决方案2】:

迟早,您可能会在代码中的其他位置(在您的用户对象之外)需要 PDO 连接对象。所以, 我建议使用一个类,该类将提供如下静态方法来在任何你想要的地方获取 PDO 连接对象。

             class Database{
                    private static $datasource='mysql:host=HOST dbname=DB';
                    private static $username='USER';
                    private static $password='PASS';
                    private static $db;

                    //make the constructor private and empty so that no code will create an object of this class.
                    private function __construct(){}

                     //the main public function which will return the required PDO object
                     public static function getDB(){
                      if(!isset(self::$db)){
                           try{
                         self::$db=new PDO(self::$datasoure,self::$username,self::$password);

                            }
                            catch(PDOExceptin $e)
                            {
                               $error=$e->getMessage(); //variable $error can be used in the database_error.php file 
                               //display database error file.
                               include('database_error.php');
                               exit();
                            }
                      }
                        return self::$db; 
                     }

                    }

然后你可以随时使用下面的静态方法来连接 PDO

                    $conn=Database::getDB();

【讨论】:

  • 这是你在 OOP 代码中引入邪恶的地方......使用静态类。
  • 谢谢。很好的解决方案。
【解决方案3】:

使用 ceejayoz 的提议或添加一个负责建立数据库连接的全局函数。该函数被编写为每个 HTTP 请求最多连接数据库 1 次:

function getPDOConnection() {
    // Thanks to the static-specifier, this variable will be initialized only once.
    static $conn = new PDO("mysql:host=HOST;dbname=DB", "USER", "PASS");

    return $conn;
}

这使您能够在整个应用程序中保持相同的连接(当然您不必在任何地方都使用该功能)。基本上,这是单例模式的一个非常简单的应用。查看documentation of the static specifier/keyword 并尝试熟悉Singleton pattern

【讨论】:

    【解决方案4】:

    变量$DBH 需要是你的类的成员变量。

    private $password; 下方,添加private $DBH;,然后您就可以从login 函数中删除新连接代码了。

    【讨论】:

    • 我尝试了你和@ceejayoz 的建议。这是有道理的。但由于某种原因,它不起作用。我收到:致命错误:在第 21 行的 /home/X/X/classes/user.php 中的非对象上调用成员函数 query()
    【解决方案5】:

    在构造函数中添加数据库连接作为参数,因此当您从用户类创建新实例时,它会自动跨实例化对象运行

    【讨论】:

      猜你喜欢
      • 2013-03-12
      • 2018-12-03
      • 2013-09-28
      • 2012-09-15
      • 1970-01-01
      • 1970-01-01
      • 2016-02-12
      • 2016-12-27
      • 1970-01-01
      相关资源
      最近更新 更多