【问题标题】:SQL query efficiency when using PHP classes使用 PHP 类时的 SQL 查询效率
【发布时间】:2013-10-21 22:05:45
【问题描述】:

我已经使用 PHP 编程很多年了,但是直到最近才开始使用类进行编程。我有以下 - 基本 - 用户类如下:

<?php
/* The class for constructing any user's information
 */

    class User {

        protected $userId, $email, $userGroup;

        protected function getEmail() {
            return $this->email;
        }

        protected function getUserId() {
            return $this->userId;
        }

        protected function getUserGroup() {
            return $this->userId;
        }


        public function __construct($userId='') {
            if($userId) {
                $select = mysql_query("SELECT userId, email, user_group FROM user WHERE userId = '$userId'");
                while($user==mysql_fetch_array($select)) {
                $this->email = $user[email];
                    $this->userId = $userId;
                    $this->userGroup = $user[user_group];
                }
            }
        }

}?>

所以我知道我可以执行以下操作

<?php
$user = new User($userId);
echo $user->getEmail();
?>

显示给定 userId 的用户电子邮件地址。我想知道的是,什么是最好的方式——使用 OOP——来显示,比如说,40 个用户的电子邮件。显然创建 40 个用户对象会很愚蠢,因为那是 40 个 SQL 查询。在给定各种参数执行 SQL 之后,您是否会简单地创建一个用于返回多个用户数组的“用户”类?

<?php
$getUsers = new Users('Tom');
// create 'Users' object where name is 'Tom'
print_r($users);
// prints the returned array of users?
?>

感谢您的帮助。希望这很清楚。

【问题讨论】:

  • $userID 通常来自哪里?如果它来自外部源,则很容易发生 SQL 注入。请切换到准备好的语句以防止这种情况发生。顺便说一句,mysql_* 函数已弃用。
  • 嗨马塞尔。我将在稍后阶段为我的 SQL 添加安全功能——这只是一个基本的早期代码,同时我在脑海中清理了我最初的问题。感谢您指出 mysql_* - 我不知道这一点。
  • @Tom :查看PDO。使用 PDO,您可以将记录集转换为 ex 数组。用户。这样你只需要 1 个 SQL 就可以得到 40 个用户作为回报

标签: php mysql sql class oop


【解决方案1】:

我会这样做(使用另一个类):

class UserRepository {
    public function getByName($name) {
        $result = mysql_query("SELECT userId, email, user_group FROM user WHERE name = '$name'");

        $users = [];

        while ($row = mysql_fetch_assoc($result)) {
            $user = new User;
            $user->email     = $row['email'];
            $user->userId    = $row['userId'];
            $user->userGroup = $row['user_group'];

            $users[] = $user;
        }

        return $users;
    }
}

补充: 下面的示例很好地说明了如何使这些类在将来需要时更易于测试和修改:

UserRepositoryInterface

interface UserRepositoryInterface {
    public function getByName($name);
    public function getByUserId($id);
}

MySqliUserRepository

class MySqliUserRepository implements UserRepositoryInterface {
    public function getByName($name) {
        // Get by name using mysqli methods here
    }

    public function getByUserId($id) {
        // Get by user id using mysqli methods here
    }
}

PDOUserRepository

class PDOUserRepository implements UserRepositoryInterface {
    public function getByName($name) {
        // Get by name using PDO methods here
    }

    public function getByUserId($id) {
        // Get by user id using PDO methods here
    }
}

用法

class Foo {

    protected $userRepository;

    public function __construct(UserRepositoryInterface $userRepository) {
        $this->userRepository = $userRepository;
    }

    public function bar() {
        $user = $this->userRepository->getByUserId(10);
    }
}

关于mysql_的使用

这可能不完全是你如何做到的,但它会给你一个想法。此外,mysql_ 已贬值,因此最好使用mysqli_PDO(我个人的建议)。 PDO 也更加 OOP 友好。

PDO:http://php.net/manual/en/book.pdo.php

mysqli_:http://php.net/manual/en/book.mysqli.php

更新:

您的个人用户类别将仅包含与该用户相关的信息。用户类不应该包含任何检索用户的方法,这是存储库的工作。因此,如果您想检索 1 个用户,而不是像现在这样在 User __construct 中执行操作,而是向 UserRepository 添加一个看起来像这样的方法:

public function getByUserId($id) {
    // Select user from db, check only 1 exists, make user object, return.
}

【讨论】:

  • @DarkBee 我已经解释过它的折旧和推荐替代品,他说他只是想知道如何去做,并在他最初的问题中使用了mysql_
  • 感谢您的回复。但是,对于单个用户特定的事物,您还会有一个单独的用户类吗?例如,$user->hasAccess($page);或类似的东西?或者你只是有一个方法,例如 checkUserAccess($userId, $page); ?感谢您的帮助
  • @TomMac 更新了我的答案。
  • @TomMac 是的,我就是这样做的,但显然如果 id 是一个整数,它看起来像:$user = $userRepository-&gt;getByUserId(41);
  • @DarkBee,不推荐使用 ext/mysql 并不意味着当前使用它的项目将用完并重写所有代码。这只是意味着 项目应该避免使用它。 Adam 使用 OP 使用的相同 API 给出答案是合理的。您的反对票是没有根据的。
【解决方案2】:

您可以使用方法来插入/检索用户,而不是使用构造来检索用户。

您可以创建方法来插入新用户、更新特定用户、检索特定用户或检索用户对象数组中的所有(带条件)等

【讨论】:

    【解决方案3】:

    我尝试将我的数据对象与数据库内容分开。在你的情况下,我会做出以下安排:

    • User 类的实例代表单个用户,无论是否在 DB 中。构造函数不会从 DB 中检索任何内容,它只是填充类属性。

    • 对于不在 DB 中的用户(例如,新创建的用户),userId 属性为 NULL(不是 '')。

    • 执行数据库操作的方法需要一个数据库接口(或至少一个对象)作为参数:

      public function save(PDO $pdo){
      }
      
    • 有一些静态方法可以从数据库中获取类实例还没有意义的东西;它们返回 User 实例或 User 集合:

      public static function fetchById(PDO $pdo, $id){
      }
      
      public static function fetchAll(PDO $pdo){
      }
      
    • 如果有意义,我会编写一个私有方法来共享公共代码:

      private static function fetch(PDO $pdo, array $filter=array()){
          $sql = 'SELECT id, email, group
               FROM user' . PHP_EOL;
          $params = array();
      
         if( isset($filter['id']) ){
             $sql .= 'WHERE id=:id';
             $params['id'] = $filter['id'];
         }
      
         //...
      }
      
      public static function fetchById(PDO $pdo, $id){
          $data = self::fetch($pdo, array('id' => $id));
          if( empty($data) ){
              return NULL;
          }else{
              reset($data);
              return curren($data);
          }
      }
      
      public static function fetchAll(PDO $pdo){
          return self::fetch($pdo);
      }
      
    • 我提到的 User 集合可以像 User 实例的数组一样简单,也可以像您自己的泛型实现一样复杂。

    这样,典型的脚本如下所示:

    // Fetch my details
    $me = User::fetchById(1);
    
    // Create a new user
    $you = new User(NULL, 'Joe', 'Guests');
    $you->save($pdo);
    $message = sprintf('User created with ID=%d', $you->userId);
    

    【讨论】:

    • 那么您的 fetch 方法是否位于 User 类下?有了这个,如果你做了 $me=User::fetchById(1);然后你能说 echo $me->userId; ?你还需要定义构造函数吗?谢谢
    • @Tom - #1 和 #2:正确。 #3:构造函数不是强制性的,但缺少一个会将$you = new User(NULL, 'Joe', 'Guests'); 变成 4 行代码。另外,请注意您将在fetch... 方法中大量使用构造函数。我的标准是在构造函数中定义重要/强制属性,并在其他地方分配额外的辅助属性(例如,使用 setter 函数),但我想重要的是要保持一致。
    • 我想我明白了。这是否意味着如果你做了 $users = User::fetchAll();,这是否意味着 $users 是一个用户对象的数组。即,回显 $user[0]->userId;会回显第一个用户的用户 ID?再次感谢
    • 没错。另请注意,Adam 的 UserRepository 是解决同一问题的更复杂的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-19
    • 2021-04-13
    • 2015-10-20
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    相关资源
    最近更新 更多