【问题标题】:PHP OOP: how to use a generic MySQL class in other classesPHP OOP:如何在其他类中使用通用 MySQL 类
【发布时间】:2011-06-04 20:37:39
【问题描述】:

我刚刚开始使用 OOP PHP,遇到了一个问题。我已经设置了一个通用的 mysql 类,它允许我连接到数据库并具有一些从表中获取记录的功能:

class mysql{
    //some lines to connect, followed by:
    public function get_record($sql)
    {
      $result = mysql_result(mysql_query($sql));
      return $result;
      //obiously it's a bit more advanced, but you get the picture.

    }
}

接下来,我有一个类来获取用户详细信息:

class user{
    __construct($id)
    {  
        $this->id = $id
    }
    public function get_username($id)
    {
         $username = get_record("SELECT name FROM users WHERE id = '".$this->id."'");
         return $username;
    }
}

我试过这个,但得到函数 get_record 未知的错误。我通过添加 $mysql = new mysql(); 解决了这个问题到用户类。

但是,必须为使用我的数据库方法(几乎是所有方法)的每个类实例化 mysql 对象感觉非常低效。

有没有办法让所有其他类都可以访问 mysql 类及其方法,而不必在每个方法中调用 mysql 类?

【问题讨论】:

  • 请不要创建 MySQL 类。周围有太多这样的东西,即使 PHP 已经内置了这样的东西。它被称为 PDO(PHP 数据库对象)。 PDO 可以转移给其他开发人员,而不得不一次又一次地找出其他人的 MySQL 类感觉毫无意义。

标签: php mysql oop class


【解决方案1】:

首先,在这种情况下您不需要使用单例 - 或者实际上,您几乎从不使用。例如,请参阅this article

其次,我认为您的 OO 设计有点偏离。面向对象编程和设计的要点是将职责隔离到单独的类中。现在,您赋予 User 类两个主要职责 - 存储/携带一个用户的相关数据,以及查询数据服务(在本例中,是一个简单的 MySQL/数据库抽象层)。

您应该首先将该功能移动到一个单独的对象中。通常,这称为服务 - 因此在这种情况下,它是 UserServiceUserService 有一个职责:提供对 User 对象的访问。所以它看起来像这样:

class UserService {
    public function __construct($mysql); // uses the mysql object to access the db. 
    public function get($id) {
        $result = $this->mysql->get_record("select x from y");
        $user = new User($result['id'], $result['name']); // assuming user has a constructor that takes an id and a name
        return $user;
    }
    public function save($user);
    public function delete($user);
}

您在请求开始时(或您需要访问用户的地方)将所有内容捆绑在一起:

$mysql = new MySQL($credentials);
$service = new UserService($mysql);
$user = $service->find(1337);

它并不完美,但它的设计要简洁得多。你的 MySQL 对象做它需要做的事情(建立一个连接,执行查询),你的用户对象是愚蠢的,你的服务只做一件事,即在实际存储层和调用它的事物之间提供一个层。

【讨论】:

  • +1 这是一个很棒的设计!用户对象应该有一个职责,就是保存用户数据。
  • 这是最好的方法!这是一个非常好的建议。更好的是使用界面,但它已经足够好了。可测试,干净。竖起大拇指
  • 我一直在寻找一种简单的方法来解释与数据库通信的最佳方法。这里方法之间的唯一区别是我一直在使用控制器而不是服务类。但是,现在我看到了这一点,我想我仍然可以使用我的控制器并将功能分离到服务中。
【解决方案2】:

设计你的mysql类被静态调用:

$username = Mysql::get_record("SELECT name FROM users WHERE id = '".$this->id."'");

http://php.net/manual/en/language.oop5.static.php

【讨论】:

  • 我宁愿称它为Mysql::get_record("SELECT name FROM users WHERE id = %d",$this->id);
  • OP 肯定有很多改进。我的回答涉及避免不断实例化的狭隘问题。
【解决方案3】:

这是一个常见问题,因此有一个常见的解决方案。 您可能知道,在软件开发中,针对常见问题的常见解决方案称为设计模式。

有两种设计模式可以帮助您解决这个问题。 在更抽象的意义上,您面临的问题是:

我怎样才能让 A 类在 B 类中可用?

单例模式

“在单例模式中,一个类可以将自己的一个实例分发给其他类。”

这并不是您要寻找的,因为您的网站可能使用多个数据库连接。但是,很多人都以这种方式使用它。

在此处阅读有关使用单例类作为数据库提供程序的一些信息: https://www.ibm.com/developerworks/library/os-php-designptrns/#N10124

更多关于 PHP 中单例模式的信息: http://www.fluffycat.com/PHP-Design-Patterns/Singleton/

另一种明智的做法是注册表模式:

注册表模式

您可以在下面的链接中找到有关注册表模式的信息,以及您正在寻找的几乎相同的实现: http://www.sitecrafting.com/blog/php-patterns-part/

更强大的是单例和注册表之间的组合。

祝你好运,享受学习 OOP PHP!

【讨论】:

  • 实际上,在这种特殊情况下,并不真正需要单例模式 - 毕竟,任何与数据库连接无关的东西都不需要访问该类,并且通过使用单例,您的整个应用程序都可以访问单例。注册表也是如此,尽管它是一个更好的选择。不,我会说数据库交互对象是一种服务,并且可以将服务分配给需要它们的对象,例如通过使用依赖注入模式。见:martinfowler.com/articles/injection.html
  • @Cthulhu - 您关于此问题不需要使用单例模式的评论是正确的,但它是此特定问题的常用解决方案。就个人而言,我对依赖注入不是很熟悉,但感谢您指出。会调查的。
  • +1 用于依赖注入...如果您没有到处都有全局变量,而是将您需要的内容注入到您的类中,它会使单元测试变得更加容易。是的,registry 和 singleton 也是全局变量......只是更伪装。
  • 单例只是变相的全局变量。不要教新程序员使用不好的做法。
【解决方案4】:

您应该将 mysql 对象传递给每个用户对象。所以它看起来像这样:

$mysql = new mysql();
$user = new user( $mysql, $id);
$name = $user->get_username();

class user {
    public function __construct($mysql, $id) {
        $this->mysql = $mysql;
        $this->id = $id;
    }
    public function get_username() {
        $username = $this->mysql->get_record("SELECT name FROM users WHERE id = '".$this->id."'");
        return $username;
    }
}

【讨论】:

    【解决方案5】:

    使用全局变量,虽然这可能不是最好的选择。

    $mysql = new mysql();
    
    function someFunction() {
      global $mysql;
      $mysql->get_record(...)
    }
    

    或者你的mysql类的静态方法(见Singleton

    class mysql {
      public static $theInstance = new mysql();
      public static function getInstance() {
        return $this->theInstance;
      }
    }
    
    function someFunction() {
      $database= mysql::getInstance();
      $database->get_record(...)
    }
    

    【讨论】:

    • 呃,请不要建议使用globales!
    【解决方案6】:

    开始想用Doctrine,比较好

    http://www.doctrine-project.org/

    【讨论】:

      猜你喜欢
      • 2012-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-20
      • 1970-01-01
      • 2014-12-21
      相关资源
      最近更新 更多