【问题标题】:Migrate class from mysql to mysqli将类从 mysql 迁移到 mysqli
【发布时间】:2016-08-11 10:23:24
【问题描述】:

我有一个简单的问题。我有那个用 mysql 扩展编写的类我的问题是如何将该类从 mysql 迁移到 mysqli 面向对象的风格而不是程序化。 我是这个 mysqli 扩展的新手。

<?php
    class DBController {
        private $host = "";
        private $user = "";
        private $password = "";
        private $database = "";

        function __construct() {
            $conn = $this->connectDB();
            if(!empty($conn)) {
                $this->selectDB($conn);
            }
        }

        function connectDB() {
            $conn = mysql_connect($this->host,$this->user,$this->password);
            return $conn;
        }

        function selectDB($conn) {
            mysql_select_db($this->database,$conn);
        }

        function runQuery($query) {
            $result = mysql_query($query);
            while($row=mysql_fetch_assoc($result)) {
                $resultset[] = $row;
            }       
            if(!empty($resultset))
                return $resultset;
        }

        function numRows($query) {
            $result  = mysql_query($query);
            $rowcount = mysql_num_rows($result);
            return $rowcount;   
        }
    }
?>

【问题讨论】:

  • 简单的做法是mysqli_ 而不是mysql_
  • 那是我尝试过的第一选择,但这种方式行不通。而且我希望迁移到面向对象的方法而不是程序。

标签: php mysql mysqli


【解决方案1】:

拥有这样的类是一个非常好的主意,但不幸的是,从mysql_* API 迁移到mysqli 类并不是那么简单。它需要大量的代码重写和思维方式的改变。

如果您计划从mysql_* API 升级,这可能意味着您之前一直在使用 PHP 4。如果您使用的是 PHP 5,那么您就是在使用 PHP 4 的思维方式。从那时起,PHP 已经走过了漫长的道路。我们现在有了正确的类、命名空间、更好的错误报告等。当涉及到数据库交互时,我们现在有两个新的扩展:mysqli 和 PDO。在这两个中您应该使用 PDO。 但是,如果您使用的是包装类,如您尝试创建的包装类,从 mysqli 更改为 PDO 应该很容易。仅出于这个原因,这样的包装类就是一个好主意。

mysqli 扩展的主要原因是保持旧扩展的熟悉语法并添加必要的新功能,例如准备好的语句和正确的错误报告。 如果您习惯于将 PHP 变量直接放入 SQL 查询中,那么您必须改变您的思维方式。您现在应该使用参数化查询并分别绑定值。

一个简单的例子说明你改进后的类可能是这样的:

<?php

class DBController {
    /**
     * mysqli instance
     *
     * @var \mysqli
     */
    private $mysqli;

    public function __construct(
        $host = null,
        $username = null,
        $passwd = null,
        $dbname = null,
        $charset = 'utf8mb4',
        $port = null,
        $socket = null
    ) {
        mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
        $this->mysqli = new \mysqli($host, $username, $passwd, $dbname, $port, $socket);
        $this->mysqli->set_charset($charset);
    }

    public function runQuery(string $sql, array $params = []): ?array {
        $stmt = $this->mysqli->prepare($sql);
        if ($params) {
            $stmt->bind_param(str_repeat("s", count($params)), ...$params);
        }
        $stmt->execute();
        if ($result = $stmt->get_result()) {
            return $result->fetch_all(MYSQLI_BOTH);
        }
        return null;
    }
}

警告:这不是此类包装类的完整实现。您很可能需要实现其他方法并根据需要添加更多逻辑。这仅用于演示目的。

首先,在构造方法中,我们应该执行 3 个步骤。启用错误报告,创建 mysqli 类的实例并设置正确的字符集(使用 MySQL 5.5 中添加的 utf8mb4,现在是标准字符集)。

您的 runQuery() 方法现在接受 2 个参数。第一个是使用占位符而不是插值的 SQL 查询,第二个是要绑定的值的数组。

您很可能不需要selectDB(),而且您绝对不需要numRows()。如果您想知道检索到的数组中的行数,可以在 PHP 中使用 count() 计算它们。

使用这样的类非常简单。

$db = new DBController('localhost', 'username', 'password', 'db_name');
$result = $db->runQuery('SELECT Id, Name FROM table1 WHERE uuid=?', ['myuuid']);
if ($result) {
    // Get the name of found record
    echo $result[0]['Name'];
} else {
    echo 'No records found';
}

如果您想将实现切换到 PDO,您可以在不改变使用方式的情况下替换该类。

class DBController {
    /**
     * PDO instance
     *
     * @var \PDO
     */
    private $pdo;

    public function __construct(
        $host = null,
        $username = null,
        $passwd = null,
        $dbname = null,
        $charset = 'utf8mb4',
        $port = null,
        $socket = null
    ) {
        $dsn = "mysql:host=$host;dbname=$dbname;charset=$charset;port=$port;socket=$socket";
        $options = [
            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
            \PDO::ATTR_EMULATE_PREPARES => false,
        ];
        $this->pdo = new PDO($dsn, $username, $passwd, $options);
    }

    public function runQuery(string $sql, array $params = []): ?array {
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetchAll();
    }
}

警告:这不是此类包装类的完整实现。您很可能需要实现其他方法并根据需要添加更多逻辑。这仅用于演示目的。

【讨论】:

    猜你喜欢
    • 2012-11-26
    • 2014-12-28
    • 1970-01-01
    • 2013-12-24
    • 2010-10-20
    • 2015-06-03
    • 2011-06-03
    • 1970-01-01
    • 2018-03-22
    相关资源
    最近更新 更多