【问题标题】:PHP classes: user class from databasePHP 类:来自数据库的用户类
【发布时间】:2013-07-30 12:41:17
【问题描述】:

所以我刚刚开始在课堂上编码,但我还没有完全理解它。所以我理解 OOP 的概念,但我有一个问题。

我将“用户”存储在数据库中,并且我想要一个用户类来获取我可能想要的关于用户的信息并执行与“用户”对象相关的事情。我明白了。

假设我有一个用户类,具有属性用户名和电子邮件我有以下代码

<?php
    class User {
        private $username;
        private $email;

        public function __construct($username,$email) {
            $this->username=$username;
            $this->email=$email;
        }
    }
?>

现在我知道我应该有 getter 和 setter 来访问用户名和电子邮件。吸气剂,我明白。但是二传手——我需要这些吗?如果我这样做了,这些是否应该为该用户更新数据库中的该字段?我的电子邮件设置器会更新数据库以及 $this->email 吗?这似乎是一个愚蠢的问题,但我想解决这个问题。

那么最后,从数据库中获取用户并创建对象的最佳方法是什么?在别处说我想从 ID 50 创建一个用户对象 - 这将从数据库中获取 ID 为 50 的用户并使用数据库电子邮件和用户名字段构造一个用户对象,最好的方法是什么?

谢谢!

【问题讨论】:

  • 我见过很多方法(有些方法是创建一个 UserManager 类来执行用户需要做的所有操作:即登录、注销、填充信息等),但是,您可能想要查看this page 并查看“对象映射”。假设您使用PDO(或显然是mysqli)连接到数据库,您可以使用对象映射,这使得填充对象变得如此简单(对于PDO,请查看setFetchMode())。
  • 尝试阅读这个完美的book。它对这个和相关的问题有广泛的解释。

标签: php database class oop


【解决方案1】:
  • 但是二传手——我需要这些吗?

这取决于。如果除了设置属性之外你不需要做任何事情,你可能不会使用一个。如果您需要检查提供的值是否匹配,例如,reg exp,或者不是太长/太短等,您可能需要一个。如果您有其他属性的设置器并且想要保留,您可能还需要一个一个统一的接口,不记得哪个属性有或没有设置器。

  • 如果我这样做了,这些是否应该为该用户更新数据库中的该字段?

如果要修改多个属性,最好只访问一次数据库。一些数据库抽象库就是这样做的:

$user->name = 'whatever';
$suer->email = 'whatever';
$user->save(); // Execute the modify query.

访问/修改数据库中的数据成本很高。

  • 那么最后从数据库中获取用户并创建对象的最佳方法是什么?

如果你正在使用,例如,mysql,你可以使用:

$users = [ ];

while($row = $result->fetch_assoc()) {
    $user = new User;
    foreach($row as $field => $value) {
       $user->$field = $value;
    }
    $users[] = $user;
}

但可能有更优雅的方式来做到这一点。

【讨论】:

  • 太好了 - 谢谢。最后一点 - 你会把这段代码放在哪里?这是类中的一个函数,即createUser,还是在您的主代码中?谢谢
  • 很难说,这取决于你。您应该阅读有关如何实现 MVC 设计模式的文章。
【解决方案2】:

Setter 用于设置对象属性值,在大多数情况下就是这样。有很多方法可以实现你想要的,基本上有关于这方面的书籍。我个人倾向于有这样的场景:

1) 使用 setter 设置对象属性

2) 调用单独的函数 commit()/save()/whatever() 将所有值写入数据库

从连续创建对象时,您最好有单独的工厂类(stackOverflow 中的好问题和答案 - What is a Factory Design Pattern in PHP?)。工厂类的思想是对象是不可变的,仅仅服务于数据容器的目的。我包含 PDO 只是为了演示目的,但当然还有其他方法(对于简单的用户表来说似乎很好)

class UserFactory
{
    private $db;

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

    public function fromID($id)
    {
        $userObject = new User();
        $q = $this->db->prepare("SELECT * FROM user WHERE u_id = :id");
        $q->bindValue(":id", $id);
        $q->setFetchMode( PDO::FETCH_INTO, $userObject);
        $q->execute();
        $q->fetch(PDO::FETCH_INTO);
        return $userObject;
    }

    public static function fromRow($row)
    {
        $userObject = new User();
        $userObject->setName($row['name']);
        $userObject->setEmail($row['name']);
        return $userObject;
    }
}

以及作为对象的集合

class UserCollection
{
    public static function getAllUsers($db)
    {
        $users = array();
        $q = $db->query("SELECT * FROM user");
        while($row = $q->fetch()){
            $users[] = UserFactory::fromRow($row);
        }
        return $users;          
    }
}

背后的想法是将数据库连接传递给静态方法,该方法将返回一个数组,其中包含从数据库初始化的所有用户对象。 这里的 getAllUsers 方法是静态的,用于演示目的,当然也可以通过创建一个将数据库连接变量作为参数的构造函数来实现。

【讨论】:

    【解决方案3】:

    您的第一个决定是是从类内的数据库中获取用户的属性,还是从类外获取。假设您在课堂外进行,那么您将不会在构造中包含任何参数,并且您可以:

    $users = array();
    while($row = $result->fetch_assoc()) {
        $user = new User();
        for($row as $field => $value) {
           $camelField = strtoupper(substr($field,0,1) . strtolower(substr($field, 1);
           $fieldClass = 'set' . $camelField;
           $user->{$fieldClass}($value);
        }
        $users[] = $user;
    }
    

    在你的课堂上,你会有像这样的二传手

    public function setName(value) {
        $this-<name = $value;
    }
    

    【讨论】:

    【解决方案4】:

    关于如何持久化对象主要有两种方法:

    活动记录/表网关

    使用这种方法,class 中的每个property 都映射到数据库table 上的某个field

    由于您使用的是 PHP,如果您使用 Zend_DbCodeIgniter Active Record,您可能已经使用过这种模式。

    这种模式的问题是它可能不适合使用大量继承并且需要深度映射的复杂领域。此外,它通常将您的类与可能加剧测试的数据库紧密耦合。

    另请参阅:WikipediaFowler

    对象-关系映射器 (ORM)

    “ORM”是一个更繁重的解决方案,它让您可以纯粹使用“对象”并完全抽象出表/数据库层。

    它还需要能够处理对象继承、组合、多态性,并且通常为引用对象的“延迟加载”提供一些功能。

    值得注意的 PHP 'ORM' 是(例如):DoctrinePropel

    另见:Wikipedia

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-12
      • 2011-12-11
      • 1970-01-01
      • 2016-10-26
      • 2019-01-26
      • 1970-01-01
      • 1970-01-01
      • 2011-08-01
      相关资源
      最近更新 更多