构建一个mysqli db连接类,其他类使用它

jco*_*ams 0 php oop mysqli

抱歉这个愚蠢的问题是一个新手在php中oop ...我有一个问题wiriting mysqli类thet返回一个连接处理程序,使我在其他类/方法中的连接处理程序.我运行一个小程序博客,想要转换为oop.这是我工作的代码示例.请在必要时为我重构.预先感谢.

$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'];
  }    
}
Run Code Online (Sandbox Code Playgroud)

我已经定义了常量,连接成功,但是选择不起作用.在索引页面上,这是

include('inc/dbc.php'); 
$db = new MyDB(); 
echo $db->getConfig(1, $db_link);  
Run Code Online (Sandbox Code Playgroud)

任何帮助表示赞赏

hak*_*kre 6

你的问题不是很具体,我觉得你并不知道你的具体问题是什么.您已经接受了一个答案,它会为您提供一些代码,但会使您处于错误的方向,因为它无法解决您的潜在问题并浪费代码.

如果你想利用PHP的mysqli扩展的面向对象接口,你应该知道的第一件事是,Mysqli该类代表了数据库连接(为程序方法命名的"链接"):

require('inc/dbc.php');

$dbConnection = new Mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
Run Code Online (Sandbox Code Playgroud)

那已经是它了.当然你可能想在这里使用一些错误处理:

if ($dbConnection->connect_error)
{
    throw new Exception(
       sprintf('(#%d) %s', $dbConnection->connect_errorno,
                $dbConnection->connect_error)
    );
}
Run Code Online (Sandbox Code Playgroud)

抛出异常而不是让我们说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);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法实际上很简单,非常相同,只有类的名称不同,需要加载它的定义:

require('inc/dbc.php');
require('inc/database.php');

$dbConnection = new DatabaseConnection(DB_HOST, DB_USER, DB_PASS, DB_NAME);
Run Code Online (Sandbox Code Playgroud)

如上所述,连接对象已经表示您的数据库连接.因此,应用程序中需要它的每个部分都必须要求它.我们来看看你的示例函数:

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'];
}
Run Code Online (Sandbox Code Playgroud)

我重命名了这个函数,我评论了第一行,即使这可能是你想要的.实际上,如果该函数是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;
    }
Run Code Online (Sandbox Code Playgroud)

如此示例所示,数据库连接已存在.但是,这是不可取的.想象一下,你不仅有选择,还有这个和那个等等,而不是更多.您将在一个类中创建另一个函数.对于一个甚至可能正常工作的小应用程序,但想象越来越多.你会得到一个非常大的课程,负责很多事情.所以这样做会很糟糕,即使你$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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这有一些扩展的错误处理,因为大多数错误都是在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
Run Code Online (Sandbox Code Playgroud)

Option对象的名称可能不太好,我试图保持示例轻量级但也提供一些分离.对于其他风格,您可能希望更喜欢某种不同类型如何访问数据库连接,因为它是Option通过它的构造函数注入的,Option不再处理有关如何创建数据库连接的详细信息.

例如,您可以使数据库连接对象更加智能,只有在第一次准备或查询实际使用时才连接到数据库.因此,对您的网站的不需要数据库连接的请求不会不必要地连接到数据库.

您可以在其他问题中找到更多示例,并且可能希望了解依赖注入.此外,你总是希望彼此分开,所以你有一些只是轻微相互连接的物体.