【问题标题】:PHP: Database Connection Class Constructor MethodPHP:数据库连接类构造方法
【发布时间】:2012-03-30 06:23:08
【问题描述】:

我是 OOP 的新手。最初我是在类内和构造函数外定义变量并为它们赋值,但今天在 Java 的 OOP 课程之后,有人告诉我这是不好的风格,应该避免。

这是我模拟的原始 PHP 数据库连接类:

class DatabaseConnection {
    private $dbHost = "localhost";
    private $dbUser = "root";
    private $dbPass = "";
    private $dbName = "test";

    function __construct() {    
        $connection = mysql_connect($this->dbHost, $this->dbUser, $this->dbPass)
            or die("Could not connect to the database:<br />" . mysql_error());
        mysql_select_db($this->dbName, $connection) 
            or die("Database error:<br />" . mysql_error());
    }
}

以上认为可以吗?还是以下更好的方法?

class DatabaseConnection {
    private $dbHost;
    private $dbUser;
    private $dbPass;
    private $dbName;

    function __construct() {
        $this->dbHost = "localhost";
        $this->dbUser = "root";
        $this->dbPass = "";
        $this->dbName = "test";

        $connection = mysql_connect($this->dbHost, $this->dbUser, $this->dbPass)
            or die("Could not connect to the database:<br />" . mysql_error());
        mysql_select_db($this->dbName, $connection) 
            or die("Database error:<br />" . mysql_error());
    }
}

我应该关注什么以确保我正确理解 OOP?

【问题讨论】:

  • 让我们暂时忘记 OOP。主机、用户、密码和数据库名的值不应该存储在配置文件中吗?
  • @Aaron,检查我更新的答案。我添加了一些项目供您在设置中考虑。
  • @JoniSalonen,谁在乎它们的存储位置?关键是它们应该在构造函数中作为参数传递。
  • @tereško 用户关心。在这两个示例中,连接数据都被硬编码在程序代码中。通常要求应从用户友好的配置文件中读取此类数据。这意味着数据库单元必须读取和解析文件,或者您需要不同的单元来执行此操作。如果您使用不同的单元,则必须设计这些单元之间的接口。另一方面,如果连接数据可以在程序中硬编码,则不需要任何这样的接口。
  • @JoniSalonen,你是在暗示DatabaseConnection 类应该知道配置吗?

标签: php oop class database-connection


【解决方案1】:

首先:这是没有意义的。

您正在为 10 岁以上的 mysql_* 函数创建一个对象包装器。这个php扩展不再维护,弃用过程有already begun。您不应将此 API 用于 2012 年的任何新项目。

相反,您应该学习如何使用PDOMySQLi 并使用prepared statements

也就是说..让我们看看你的代码:

  • 构造函数应接收创建新实例所需的所有参数,参数不应在类定义中硬编码。如果您需要同时使用两个数据库怎么办?
  • 创建连接时,应将其存储在对象的范围变量中。类似于$this-&gt;connection = mysql_conn... 的东西。相反,您将其存储在局部变量中,在构造函数完成后您“松散”
  • 您不应该对所有内容都使用private 变量。它们对扩展原始类的类不可见。除非是故意的,否则您应该为此选择protected
  • or die('..') 位最多。如果连接失败,请不要停止整个应用程序。相反,您应该抛出一个exception,然后可以在构造函数之外对其进行处理。

【讨论】:

  • 如果他想连接到另一个数据库,他可以在他的查询中指定数据库名称......不要这么屌。天啊
  • @michaelhanon 你真的看过他的代码吗?只是命名连接没有任何好处。而且您可能应该阅读有关 OCP 的信息,以免听起来像这样的工具。
  • @michaelhanon 我会比 terēsko 更糟糕的抨击,尤其是那些暗示 cmets 中无用的东西..
【解决方案2】:

嗯,它还不会运行。您需要更改变量以使其与您的连接参数匹配:

$dbHost = "localhost";

应该是

$this->dbHost = 'localhost';

我通常根本不会将我的登录参数放在课程中。创建对象时,我会将它们传递给构造函数。使用外部配置文件,这样您就可以在多个构建中实际使用此类。 :)

更新::

好的,这里有一些小的 OOP 配置金块可以帮助您构建动态数据库类。

  • 查看http://redbeanphp.com/ 它将允许您进行伪 ORM 风格的数据建模。超级容易安装,并且非常容易让您的数据库启动和运行。 http://redbeanphp.com/manual/installing

  • 创建一个配置文件,其中包含常量、模板设置、常用函数和 AUTOLOADER 配置文件是在版本控制环境中工作的关键。 :)

  • 将您的数据库类构建为抽象类http://php.net/manual/en/language.oop5.abstract.php

    abstract class Database
    {
      public function update()
      {
      }
    
      public function deactivate()
      {
      }
    
      public function destroy()
      {
      }
    
      //etc.
    }
    
    class MyAppObject extends Database
    {
    }
    
  • 将所有类文件放入库文件夹中,然后将配置文件放入该库中。现在,为了让您的生活更轻松,您可以在需要时使用自动加载器功能使您的类栩栩如生,而无需包含任何特定的类。见下文:

    //note: this is never explicitly instantiated
    //note: name your files like this: MyAppObject.class.php  
    function my_fancypants_autoloader( $my_class_name )
    {
      if( preg_match( "%^_(Model_)%", $my_class_name ) ) return;
      require_once( "$my_class_name.class.php" );
    }
    spl_autoload_register( 'my_fancypants_autoloader' );
    
    • 现在您只需在 .php 文件中包含一个配置文件即可访问您的类。

希望这能为您指明正确的方向!祝你好运!

【讨论】:

    【解决方案3】:

    由于您只在__construct 方法中使用它们,因此您不需要它们作为类属性。只有$connection 必须保留以供以后使用恕我直言。

    最好不要为这些参数提供任何默认值,而是让它们从外部设置。

    $db = new DatabaseConnection("localhost", "user", "password", "db");
    

    它们已经有大量的 PHP 工具,找到它们,阅读它们并从中学习。首先,使用PDO,Java 中正确的东西在 PHP 中并不总是正确的。

    【讨论】:

      【解决方案4】:

      后者可能更好,但有一个调整:将一些参数传递给构造函数,即连接信息。

      您的第一个示例仅在您有一个数据库连接并且您乐于对连接值进行硬编码(您不应该这样做)时才有用。第二个例子,如果你添加一个$name参数作为参数,可以用来连接多个数据库:

      我是 OOP 的新手。最初我是在类内和构造函数外定义变量并为它们赋值,但今天在 Java 的 OOP 课程之后,有人告诉我这是不好的风格,应该避免。

      class DatabaseConnection {
          private $dbHost;
          private $dbUser;
          private $dbPass;
          private $dbName;
      
          function __construct($config) {
              // Process the config file and dump the variables into $config
              $this->dbHost = $config['host'];
              $this->dbName = $config['name'];
              $this->dbUser = $config['user'];
              $this->dbPass = $config['pass'];
      
              $connection = mysql_connect($this->dbHost, $this->dbUser, $this->dbPass)
                  or die("Could not connect to the database:<br />" . mysql_error());
              mysql_select_db($this->dbName, $connection) 
                  or die("Database error:<br />" . mysql_error());
          }
      }
      

      所以使用这种风格,你现在有了一个更有用的类。

      【讨论】:

        【解决方案5】:

        这是我的,效果很好:

        class Database
        {
           private static $_dbUser = 'user';
           private static $_dbPass = 'pwd';
           private static $_dbDB = 'dbname';
           private static $_dbHost = 'localhost';
           private static $_connection = NULL;
        
           /**
            * Constructor
            * prevents new Object creation
            */
        
           private function __construct(){
           }
        
           /**
            * Get Database connection
            * 
            * @return Mysqli
            */
        
           public static function getConnection() {
              if (!self::$_connection) {
             self::$_connection = @new mysqli(self::$_dbHost, self::$_dbUser, self::$_dbPass, self::$_dbDB);
        
                 if (self::$_connection -> connect_error) {
                    die('Connect Error: ' . self::$_connection->connect_error);
                 }
              }
              return self::$_connection;
           }
        }
        

        通过将__construct 设为空,可以防止从任何地方实例化新类。然后,将函数设置为静态,所以现在我需要做的就是获得我的连接是Database::getConnection() 这一切都在include 文件中,在服务器上的受密码保护的文件夹中,并且只包含在每个类文件中。这还将在尝试另一个连接之前检查连接是否已经打开。如果已经建立了一个,则将打开的连接传递给该方法。

        【讨论】:

        • 如果可能的话(在大多数情况下可能的)不要使用root用户!!!如果出现安全漏洞,您的数据库就完蛋了。创建具有最小权限的第二个帐户。我的辅助帐户甚至无法删除记录。如果我需要能够删除记录,我将创建另一个数据库类,其用户仅具有该权限,并且只为我需要的方法调用它。
        • 如果你使用全静态类,那么它就不是 OOP。它只是带有全局变量的旧程序代码。你只需将它包装在一个类中,它就像命名空间一样。
        • 还有,拜托! FFS,在不需要的地方停止使用@ 运算符。隐藏错误通常是你能做的最糟糕的事情。
        • 我在那里使用它是因为我的用户不需要知道我无法建立数据库连接,只是为了“稍后再试”。这是我使用@ 的唯一实例
        • 这就是为什么我们有ini_set('dispaly_errors', false); 用于生产代码。用户不需要知道,但维护者需要。至于那个“一个连接”c**p,请去了解dependency injection是什么..
        【解决方案6】:
        <?php
        
            class config
            {
                private $host='localhost';
                private $username='root';
                private $password='';
                private $dbname='khandla';
        
                function __construct()
                {   
                    if(mysql_connect($this->host,$this->username,$this->password))
                    {
                        echo "connection successfully";
                    }
                }
                function db()
                {
                    mysql_select_db($this->$dbname);
                }
            }
        
            $obj=new config();
        ?>
        

        【讨论】:

        猜你喜欢
        • 2013-05-28
        • 2011-03-14
        • 2014-06-11
        • 2014-07-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-12
        • 1970-01-01
        相关资源
        最近更新 更多