0

抱歉这个愚蠢的问题是 php 中的 oop 新手……我有一个问题,我在编写一个 mysqli 类时会返回一个连接处理程序,该处理程序使我能够在其他类/方法中使用连接处理程序。我运行一个小型程序博客 n 想转换为 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'];
  }    
}

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

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

任何帮助表示赞赏

4

3 回答 3

6

你的问题不是很具体,我感觉你并没有真正意识到你的具体问题是什么。您已经接受了一个答案,该答案为您提供了一些代码,但将您置于错误的方向,因为它不能解决您的潜在问题并浪费代码。

如果您想利用 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不再处理如何创建数据库连接的细节。

例如,您可以使数据库连接对象更智能,仅在第一次实际使用准备或查询时连接到数据库。这样对您网站的不需要数据库连接的请求就不会不必要地连接到数据库。

您可以在其他问题中找到更多示例,并且您可能想了解依赖注入。此外,您总是希望将事物彼此分开,因此您有一些彼此仅轻微连接的对象。

于 2012-09-20T00:53:30.507 回答
3

我建议在类中也将连接移动到数据库:

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);
于 2012-09-19T11:45:21.750 回答
2

我建议您将 mysqli 类包装在一个新的类中,而不是对其进行扩展:对于那些需要配置的类,只需包含具有依赖注入的配置即可。这给您带来的好处是,您需要配置的代码不需要了解方式,配置获取其值。如果您稍后决定从iniFile 解析配置,您只需要更改配置类,或者更好的是,编写一个实现配置接口的新类并注入新的配置类。

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);
}

像这样使用它:

$mysqli = new mysqli('localhost', 'root', 'pw', 'my_db');
$config = new Configuration($mysqli);

var_dump($config->get(0));
于 2012-09-19T12:23:29.130 回答