【问题标题】:Is this the correct way to do this PHP class?这是做这个PHP类的正确方法吗?
【发布时间】:2009-12-25 18:14:38
【问题描述】:

您好,我正在学习更多关于在 PHP 中使用类的知识。我知道下面的代码很垃圾,但我需要帮助。

如果我朝着正确的方向前进,谁能告诉我。

我的目标是将此类包含到用户配置文件页面中,当创建新的配置文件对象时,我希望它从 mysql 检索所有配置文件数据,然后我希望能够显示任何项目在页面上使用类似这样的东西

$profile = New Profile;
echo $profile->user_name;

到目前为止,这是我的代码,请告诉我到目前为止出了什么问题,或者我是否朝着正确的方向前进?

也不是使用 echo $profile->user_name;对于 50 多个配置文件 mysql 文件,有时我需要对数据进行处理,例如加入日期和出生日期有其他必须运行的代码才能转换它们,如果记录为空,那么我想显示一个替代值,所以有了这些知识,我应该使用方法吗?喜欢 50 多种不同的方法?

<?PHP
//Profile.class.php file

class Profile
{
    //set some profile variables
    public $userid;
    public $pic_url;
    public $location_lat;
    public $location_long;
    public $user_name;
    public $f_name;
    public $l_name;
    public $country;
    public $usa_state;
    public $other_state;
    public $zip_code;
    public $city;
    public $gender;
    public $birth_date;
    public $date_create;
    public $date_last_visit;
    public $user_role;
    public $photo_url;
    public $user_status;
    public $friend_count;
    public $comment_count;
    public $forum_post_count;
    public $referral_count;
    public $referral_count_total;
    public $setting_public_profile;
    public $setting_online;
    public $profile_purpose;
    public $profile_height;
    public $profile_body_type;
    public $profile_ethnicity;
    public $profile_occupation;
    public $profile_marital_status;
    public $profile_sex_orientation;
    public $profile_home_town;
    public $profile_religion;
    public $profile_smoker;
    public $profile_drinker;
    public $profile_kids;
    public $profile_education;
    public $profile_income;
    public $profile_headline;
    public $profile_about_me;
    public $profile_like_to_meet;
    public $profile_interest;
    public $profile_music;
    public $profile_television;
    public $profile_books;
    public $profile_heroes;
    public $profile_here_for;
    public $profile_counter;

    function __construct($session)
    {
    // coming soon
    }

    //get profile data
    function getProfile_info(){
        $sql = "SELECT user_name,f_name,l_name,country,usa_state,other_state,zip_code,city,gender,birth_date,date_created,date_last_visit,   
        user_role,photo_url,user_status,friend_count,comment_count,forum_post_count,referral_count,referral_count_total,
        setting_public_profile,setting_online,profile_purpose,profile_height,profile_body_type,profile_ethnicity,
        profile_occupation,profile_marital_status,profile_sex_orientation,profile_home_town,profile_religion,
        profile_smoker,profile_drinker,profile_kids,profile_education,profile_income,profile_headline,profile_about_me,
        profile_like_to_meet,profile_interest,profile_music,profile_television,profile_books,profile_heroes,profile_here_for,profile_counter
        FROM users WHERE user_id=$profileid AND user_role > 0";
        $result_profile = Database::executequery($sql);

        if ($profile = mysql_fetch_assoc($result_profile)) {
            //result is found so set some variables
            $this->user_name = $profile['user_name'];
            $this->f_name = $profile['f_name'];
            $this->l_name = $profile['l_name'];
            $this->country = $profile['country'];
            $this->usa_state = $profile['usa_state'];
            $this->other_state = $profile['other_state'];
            $this->zip_code = $profile['zip_code'];
            $this->city = $profile['city'];
            $this->gender = $profile['gender'];
            $this->birth_date = $profile['birth_date'];
            $this->date_created = $profile['date_created'];
            $this->date_last_visit = $profile['date_last_visit'];
            $this->user_role = $profile['user_role'];
            $this->photo_url = $profile['photo_url'];
            $this->user_status = $profile['user_status'];
            $this->friend_count = $profile['friend_count'];
            $this->comment_count = $profile['comment_count'];
            $this->forum_post_count = $profile['forum_post_count'];
            $this->referral_count = $profile['referral_count'];
            $this->referral_count_total = $profile['referral_count_total'];
            $this->setting_public_profile = $profile['setting_public_profile'];
            $this->setting_online = $profile['setting_online'];
            $this->profile_purpose = $profile['profile_purpose'];
            $this->profile_height = $profile['profile_height'];
            $this->profile_body_type = $profile['profile_body_type'];
            $this->profile_ethnicity = $profile['profile_ethnicity'];
            $this->profile_occupation = $profile['profile_occupation'];
            $this->profile_marital_status = $profile['profile_marital_status'];
            $this->profile_sex_orientation = $profile['profile_sex_orientation'];
            $this->profile_home_town = $profile['profile_home_town'];
            $this->profile_religion = $profile['profile_religion'];
            $this->profile_smoker = $profile['profile_smoker'];
            $this->profile_drinker = $profile['profile_drinker'];
            $this->profile_kids = $profile['profile_kids'];
            $this->profile_education = $profile['profile_education'];
            $this->profile_income = $profile['profile_income'];
            $this->profile_headline = $profile['profile_headline'];
            $this->profile_about_me = $profile['profile_about_me'];
            $this->profile_like_to_meet = $profile['profile_like_to_meet'];
            $this->profile_interest = $profile['profile_interest'];
            $this->profile_music = $profile['profile_music'];
            $this->profile_television = $profile['profile_television'];
            $this->profile_books = $profile['profile_books'];
            $this->profile_heroes = $profile['profile_heroes'];
            $this->profile_here_for = $profile['profile_here_for'];
            $this->profile_counter = $profile['profile_counter'];
        }
    //this part is not done either...........
    return $this->pic_url;
    }
}

【问题讨论】:

  • Veeti 回答的后半部分特别有用。任何严肃的 Web 开发都将涉及到框架的使用。在 Web 开发中重新发明轮子是没有意义的。您可能想看看 CakePHP 或类似的框架。

标签: php mysql class


【解决方案1】:

您可能想看看 PHP 的 magic methods,它允许您创建少量方法(通常是“get”和“set”方法),然后您可以使用它们来返回/设置大量私有/受保护的变量很容易。然后,您可以拥有例如以下代码(抽象但希望您能理解):

class Profile
{
  private $_profile;

  // $_profile is set somewhere else, as per your original code

  public function __get($name)
  {
    if (array_key_exists($name, $this->_profile)) {
      return $this->_profile[$name];
    }
  }

  public function __set($name, $value)
  {
    // you would normally do some sanity checking here too
    // to make sure you're not just setting random variables

    $this->_profile[$name] = $value;
  }
}

正如其他人所建议的那样,也许研究像 ORM 或类似的东西(Doctrine、ActiveRecord 等)可能是一个值得练习的东西,上面所有的东西都为你完成了:-)

编辑:我可能应该提到在您实现上述内容后您将如何访问属性(为了完整性!)

$profile = new Profile;

// setting
$profile->user_name = "JoeBloggs";

// retrieving
echo $profile->user_name;

这些将使用上面定义的魔法方法。

【讨论】:

  • +1 用于魔术,并使用 ORM(我个人有点像 Doctrine)而不是重新发明轮子——请注意,魔术方法也必须在 IDE 中不自动完成带来不便(除非你也使用了正确的文档块;;据我记得,Doctrine 会生成这些,顺便说一句)
  • 每个个人资料页面大约有 50 个不同的项目要显示,其中很多项目需要在显示之前进行修改,例如某些日期已转换,我想显示一个替代值如果结果为空,我相信我可以将所有这些功能添加到您的示例中,但如果我不使用 get/set,我应该用 50 种不同的方法构建一个类吗?也许构造方法可以从数据库中检索数据,然后其他方法将显示结果
  • @jason 您可以按照我的示例将其构建为单个对象(我假设您将从数据库中获取的数组等作为单行),或者您可以拥有 50 个单独的类成员变量。您可以根据要求的 $name 将默认值构建到上述方法中,或者您可以为每个项目创建 get*() 方法。
【解决方案2】:

您应该考虑创建某种类来抽象这一切,以便您的“配置文件”可以扩展它,并且您编写的所有功能都已经到位。

您可能对现成的解决方案感兴趣 - 这些称为对象关系映射器

您应该查看PHP ActiveRecord,它应该可以让您轻松执行此类操作,而无需自己编写 ORM 代码。

其他类似的库包括DoctrineOutlet

【讨论】:

    【解决方案3】:

    不要使用一大堆公共变量。在最坏的情况下,将其设为一个变量,例如$profile。然后所有字段都是$profile['body_type'] 或其他。

    【讨论】:

    • 对每个字段使用一个属性有一个优势:在任何体面的 IDE 中自动完成(你的解决方案没有这个优势——至少,除非你定义了正确的文档块)
    • 您如何看待切换到对每个项目使用一种方法,这样我就可以在每个输出上运行其他代码,例如将数字变量上的数字和从数据库返回的任何变量转换为空白,我可以使方法 cshow 替代文本?
    【解决方案4】:

    在我看来,这就像一个数据类,Martin Fowler 在他的书Refactoring 中称之为code smell

    数据类就像孩子一样。他们作为起点还可以,但作为一个成年对象参与,他们需要承担一些责任。

    他指出,就像这里的情况一样,

    在早期阶段,这些类可能具有公共字段。如果是这样,您应该在任何人注意到之前立即Encapsulate Field

    如果您将许多字段转换为一个或多个关联数组,那么 Fowler 的建议是

    检查它们是否被正确封装并应用 Encapsulate Collection 如果不是。在任何不应更改的字段上使用 Remove Setting Method

    稍后,当您的 Profile 类被赋予行为,并且其他类(其客户端)使用这些行为时,将其中一些行为(以及任何相关数据)移动到客户端可能是有意义的使用 Move Method 的类。

    如果您不能移动整个方法,请使用 Extract Method 创建一个可以移动的方法。一段时间后,您可以开始在 getter 和 setter 上使用 Hide Method

    【讨论】:

    • 当然,这个建议相当笼统。我喜欢你的课的一件事是你通过$session 而不是依赖一些全局数据。这称为依赖注入,它可以在单元测试中为您的类提供虚拟数据。
    【解决方案5】:

    通常,会创建一个类来将您可以的事情抽象为一个对象(您可以发送的消息)。您创建它的方式更像是一本字典:PHP 语法与数据库字段的一对一映射。这并没有太多的附加价值:您插入了一层额外的间接层而没有明显的好处。

    相反,该类必须包含所谓的“状态”,例如某个表的 id 字段,以及一些方法(一些...),例如"addressString()", "marriedTo()", ....

    如果您担心性能,可以缓存表的字段,这是一个完全不同的问题,应该由另一个可以聚合的类(Cache 类或其他类)实现)。

    我在这个设计中看到的主要 OO 违规是违反“告诉,不要问”原则。

    【讨论】:

    • 你觉得我制作了 50 种不同的方法来处理我需要显示的项目,例如,如果数据库中的项目是日期,那么显示该日期的方法将运行其他代码来格式化它显示的方式,然后将其打印到屏幕上,这些方法中的每一个都会检查值是否为空,如果是,那么类方法将使其显示替代文本。这不合适吗?
    • 我宁愿添加一个方法来呈现“showingHtml”代码,以尝试不暴露对象的内容,而是询问它希望如何显示为例如一个html表单。在 Holub 的一篇文章中,这个想法被创造为 Visual Proxy 模式。这篇文章也对一些基本的 OO 概念进行了非常简洁的解释(参见 javaworld.com/javaworld/jw-09-1999/jw-09-toolbox.html
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-08
    • 2013-09-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多