你的问题不是很具体,我感觉你并没有真正意识到你的具体问题是什么。您已经接受了一个答案,该答案为您提供了一些代码,但将您置于错误的方向,因为它不能解决您的潜在问题并浪费代码。
如果您想利用 PHP 的 mysqli 扩展的面向对象接口并从中受益,您应该知道的第一件事是,Mysqli
该类已经表示数据库连接(“链接”,因为它以过程方法命名):
require('inc/dbc.php');
$dbConnection = new Mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
已经是这样了。当然,您可能想在这里使用一些错误处理:
if ($dbConnection->connect_error)
{
throw new Exception(
sprintf('(#%d) %s', $dbConnection->connect_errorno,
$dbConnection->connect_error)
);
}
抛出异常而不是假设die('message')
已经完成,因为您可以轻松创建异常处理程序,以便您可以从中心位置向用户显示更有用的响应,而不是处理出现的每个异常错误情况(实际上是在该位置会在哪里die
)。
您还可以记录并邮寄回溯,以便更轻松地修复问题。当然,您不需要使用异常,但是经验法则是die
仅在您在一周内丢弃的脚本中使用,并且它不适用于面向对象的设计。
由于您在需要数据库连接的所有地方都需要此代码,因此您可以创建自己的连接对象以将这些部分组合在一起,因为它们属于一起:
class DatabaseException extends Exception
{
}
class DatabaseConnection extends Mysqli
{
public function __construct($host, $user, $password, $database = "", $port = NULL, $socket = NULL) {
parent::__construct($host, $user, $password, $database, $port, $socket);
$this->throwConnectionExceptionOnConnectionError();
}
private function throwConnectionExceptionOnConnectionError() {
if (!$this->connect_error) return;
$message = sprintf('(%s) %s', $this->connect_errno, $this->connect_error);
throw new DatabaseException($message);
}
}
用法实际上非常简单并且非常相同,只是类的名称有所不同,并且需要加载它的定义:
require('inc/dbc.php');
require('inc/database.php');
$dbConnection = new DatabaseConnection(DB_HOST, DB_USER, DB_PASS, DB_NAME);
如所写,连接对象已经代表您的数据库连接。因此,应用程序中需要它的每个部分都必须请求它。让我们回顾一下您的示例函数:
function getOption($id, $db_link)
{
// $db_link = $this->db_link;
$res = mysqli_query($this->db_link,"SELECT * from config where id='1'");
$row = mysqli_fetch_array($res);
return $row['option'];
}
我重命名了函数并评论了第一行,即使这可能是你想要的。实际上,如果该函数是DatabaseConnection
对象的一部分,它可以像这样工作:
class DatabaseConnection extends Mysqli
{
...
public function getOption($id) {
$statement = $this->prepare('SELECT `option` FROM config WHERE id=?');
$statement->bind_param('i', $id);
$statement->execute();
$statement->bind_result($option);
$statement->fetch();
$statement->close();
return $option;
}
如本例所示,数据库连接已经存在。但是,这是不可取的。想象一下,你不仅有选择,还有这个、那个等等等等等等。您将在一个类中创建一个又一个函数。好吧,对于一个甚至可以正常工作的小应用程序,但想像得越来越多。你会得到一个非常大的班级,负责很多事情。所以这样做会很糟糕,即使你可以使用$this
已经准备好的语句。
另请注意,您应该准备声明。这已经在这里回答了无数次,如果您不习惯,请阅读它,值得一读。有更好的方法可以在进入面向对象的过程中不重复代码(DRY:不要重复自己)(您甚至应该已经使用程序来做到这一点)。
为了将所有这些都放在一个类中会是一个问题,而是将它放在它自己的类中:
class DatabaseModelBase
{
protected $connection;
public function __construct(Connection $connection) {
$this->connection = $connection;
}
protected function prepare($query) {
$connection = $this->connection;
$statement = $connection->prepare($query);
if (!$statement) {
throw new DatabaseException(
sprintf('(%s) %s', $connection->error, $connection->errno)
);
}
return $statement;
}
}
class Option extends DatabaseModelBase
{
public function find($id) {
$statement = $this->prepare('SELECT `option` FROM config WHERE id=?');
$statement->bind_param('i', $id);
$statement->execute();
$statement->bind_result($option);
$statement->fetch();
$statement->close();
return $option;
}
}
这再次具有一些扩展的错误处理,因为大多数错误是在 SQL 查询中发生的。正如您所看到的,获取某些特定数据的单个函数被放置在它自己的类中。您可以使用此类类对特定数据类型的获取和更新进行分组。
完整用法:
$dbConnection = new Connection(DB_HOST, DB_USER, DB_PASS, DB_NAME);
$option = new Option($dbConnection);
$optionValue = $option->find(1);
echo $optionValue; # value for option with ID1
对象的名称Option
可能不太好,我试图使示例保持轻量级,但也提供了一些分离。Option
对于其他场景,您可能希望更喜欢一些不同的方式来访问数据库连接,因为它是通过它的构造函数注入的,Option
不再处理如何创建数据库连接的细节。
例如,您可以使数据库连接对象更智能,仅在第一次实际使用准备或查询时连接到数据库。这样对您网站的不需要数据库连接的请求就不会不必要地连接到数据库。
您可以在其他问题中找到更多示例,并且您可能想了解依赖注入。此外,您总是希望将事物彼此分开,因此您有一些彼此仅轻微连接的对象。