Php 构建一个mysqli数据库连接类,其他类使用它
对于这个愚蠢的问题很抱歉,我是php中oop的新手……我有一个问题,编写一个mysqli类时会返回一个连接处理程序,使我能够在其他类/方法中使用连接处理程序。我运行了一个小程序博客,希望将其转换为oop。 下面是我的工作代码示例。请在必要时为我重构。先谢谢你Php 构建一个mysqli数据库连接类,其他类使用它,php,oop,mysqli,Php,Oop,Mysqli,对于这个愚蠢的问题很抱歉,我是php中oop的新手……我有一个问题,编写一个mysqli类时会返回一个连接处理程序,使我能够在其他类/方法中使用连接处理程序。我运行了一个小程序博客,希望将其转换为oop。 下面是我的工作代码示例。请在必要时为我重构。先谢谢你 $db_link = mysqli_connect(DB,HOST,DB_USER,DB,PASS,DB_NAME) or die(mysql_error()); class myDB extends mysqli { public f
$db_link = mysqli_connect(DB,HOST,DB_USER,DB,PASS,DB_NAME) or die(mysql_error());
class myDB extends mysqli
{
public function getConfig($id, $db_link) // thanks cbuckley
{
$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'];
}
}
我已经定义了常量,连接成功,但选择不起作用。在索引页上,这是
include('inc/dbc.php');
$db = new MyDB();
echo $db->getConfig(1, $db_link);
非常感谢您的帮助我建议将“连接到数据库”也移动到类中:
class myDB extends mysqli
{
private $link;
public function Connect()
{
$this->link = mysqli_connect(DB,HOST,DB_USER,DB,PASS,DB_NAME) or die(mysql_error());
}
public function getConfig($id) // thanks cbuckley
{
$res = mysqli_query($this->link,"SELECT * from config where id='$id'");
$row = mysqli_fetch_array($res);
return $row['option'];
}
}
然后像这样使用它:
include('inc/dbc.php');
$db = new MyDB();
$db->Connect();
echo $db->getConfig(1);
$mysqli = new mysqli('localhost', 'root', 'pw', 'my_db');
$config = new Configuration($mysqli);
var_dump($config->get(0));
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;
}
我建议您将mysqli类包装在一个新类中,而不是扩展它: 对于那些需要配置的类,只需包含带有依赖项注入的配置。这给您带来了好处,您需要配置的代码不需要知道配置获取其值的方式。 如果以后决定从INI文件解析配置,只需更改配置类,或者编写一个实现ConfigurationInterface的新类并注入新的ConfigurationClass
class Configuration implements ConfigurationInterface{
private $mysqli;
public function construct(mysqli $mysqli) {
$this->mysqli = $mysqli;
}
public function get($key)
{
// You should escape this query to prevent SQL-injection
$res = $this->mysqli->query("SELECT * from config where id='$key'");
$row = $res>fetch_array();
return $row['option'];
}
}
interface ConfigurationInterface {
public get($key);
}
像这样使用它:
include('inc/dbc.php');
$db = new MyDB();
$db->Connect();
echo $db->getConfig(1);
$mysqli = new mysqli('localhost', 'root', 'pw', 'my_db');
$config = new Configuration($mysqli);
var_dump($config->get(0));
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;
}
你的问题不是很具体,我感觉你还没有真正意识到你的具体问题是什么。您已经接受了一个答案,该答案为您提供了一些代码,但将您带入了错误的方向,因为它无法解决您的根本问题,并且浪费了代码 如果您想利用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);
如前所述,connection对象已表示您的数据库连接。因此,应用程序中需要它的每个部分都必须请求它。让我们回顾一下您的示例函数:
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对象的一部分,它可以如下工作:
include('inc/dbc.php');
$db = new MyDB();
$db->Connect();
echo $db->getConfig(1);
$mysqli = new mysqli('localhost', 'root', 'pw', 'my_db');
$config = new Configuration($mysqli);
var_dump($config->get(0));
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来准备语句
还要注意的是,你应该准备陈述。这个问题在这里已经被回答了很多次,如果你不习惯,读一读,这是值得的。有更好的方法可以避免重复代码枯燥:在进入面向对象时不要重复自己,甚至应该已经使用过程化方法来完成
因此,如果要将所有这些都放在一个类中,这将是一个问题,您可以将其放在它自己的类中:
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
选项对象的名称可能不太好,我试图保持示例的轻量级,但也提供了一些分离。对于其他场景,您可能希望选择某种不同的方式来访问db连接,因为它是通过其构造函数注入Option的,Option不再处理如何创建数据库连接的细节
例如,只有在第一次实际使用准备或查询时才连接到数据库,才能使数据库连接对象更智能。因此
对不需要数据库连接的网站的请求不会不必要地连接到数据库
您可以在其他问题中找到更多示例,您可能希望了解依赖项注入。此外,您总是希望将事物彼此分开,因此您有一些对象彼此之间仅轻轻连接
呜呜……谢谢兄弟,我欠你一个……它工作得很好!!!。。。hpe如果你不介意我们成为朋友,因为我在oop过程中遇到了很多麻烦…非常感谢。这有点复杂,显然没有理由从mysqli扩展myDB类。那你为什么这么做?你不认为这对提出问题的开发人员有误导性吗?阅读OO、搜索封装、关注点分离、可测试代码等。编程是一项严肃的职业。@JvdBerg:当然,但你在这里做的完全相反。这就是我问的真正原因。你的理由是什么?专业精神并非如此。首先,使用Mysqli的过程接口是程序化的,而不是面向对象的。你可以说你把它封装起来了,但是这完全是多余的,因为你从mysqli扩展,使用父级的ctor和$this就可以了,不是吗?然后是可测试代码。数据库配置为全局静态常量,怎么能不发出警告呢?这个名单可以一直列下去。那么你的理由是什么呢?我正试图帮助那些在OO编程中迈出第一步的人!如果你想讨论这个问题,你可以随时提出问题。谢谢你的建议,但我真的不明白你的逻辑。请注意,这是一个php编程范例的新手。请简化您的代码。谢谢,我希望现在更清楚了。。。关于转义,我相信你会在API中找到,我不太了解mysqli,因为我使用PDO而不是headis,你为什么不使用PDO呢?许多PHP用户都在谈论PDO对他们来说更容易使用,它提供了与mysqli和其他类似的功能?只是问一下,我很想知道。嗯……哈克拉,这是对我问题的广泛回答。。非常感谢,我将使用这段代码,并就结果和我可能遇到的任何问题返回给您…谢谢,是的,这有点广泛,我想第二部分有点模糊。这一部分也主要影响了你将如何做/你的风格,我认为第一部分对于了解Mysli OO的基础知识更为重要。它有点广泛,因为我认为你把多个东西放在一起,你认为是问题,甚至可能是一个问题。尽量将问题隔离一点,这通常有助于更容易地找到解决方案。这是伴随实践而来的东西,在编程中永远不会停止,无论你的练习时间长短。再次感谢你,请你给我一个完整的工作班。加入所有必要的函数及其对相应对象的调用…感谢你在下面的示例中创建你自己的连接对象,以将这些部分合并在一起,因为它们属于一起:-这就是整个数据库连接类。而且它也应该起作用,用法示例是最后一个示例。另外请注意,您的常量名称有点误导,我更改了它们。使用起来仍然很混乱..很抱歉我的错误。枯燥的交互非常糟糕,在oop中没有经验..创建自己的连接线后的代码?.我是否在编辑器上复制该代码和paset,使用示例和配置值将返回?