草庐IT

php - 重构困境 : User Account Functionality in PHP

coder 2024-04-16 原文

我正在用 PHP 编写一个用户帐户系统,重点是安全性,但我一直坚持将其重构为更简洁、更有用的东西。

问题是试图将用户帐户功能组合在一起,但在不同的类中。我现在这样做的方式是,有一堆带有公共(public)静态方法的类都将 $username 作为第一个参数,并且它们使用其他静态方法,也将相同的 $username 作为第一个参数传递。显然,OOP 是一种更好的方法,特别是因为每个方法都必须 strtolower 用户名才能进行数据库查询,并且必须处理提供的用户名根本不存在的情况。

将所有内容都放在“User”类中的问题是它会很大,并且在同一个文件中会有很多完全不相关的代码。例如,更改密码代码不需要调用与验证用户电子邮件或更改用户(无关)设置相关的方法。

我可以有两个类:User 和 AuthenticatedUser,其中 AuthenticatedUser 继承了 User。 User 将实现所有可能的功能,而无需用户登录,而 AuthenticatedUser 将是所有需要登录的功能——例如访问用户的加密数据。维护代码可以使用 User 对象,而 GUI 代码会在用户登录后获得一个 AuthenticatedUser 对象。但我不想将所有功能都塞进 User。

下面是一些与用户帐户相关的操作的列表,只是为了说明为什么它们不能全部放在一个类中:

  • 登录
  • 如果在过去 Y 分钟内 >=X 次尝试,则锁定用户(包括确定用户是否被锁定、为尝试计数添加标记等的方法)。
  • 通过电子邮件循环绕过锁定
  • 更改密码
  • 管理员更改密码(强制)
  • 密码重置(电子邮件循环)(包括启动重置、验证电子邮件 token 等的方法)
  • 设置/获取以明文形式存储的用户数据
  • 设置/获取加密的用户数据
  • 设置/获取帐户设置(是否允许重设密码?密码失败时锁定帐户?是否允许使用电子邮件循环绕过锁定?等)理想情况下,这些设置应设置/获取行为取决于行为的代码附近他们。
  • 以正确的大小写获取用户的用户名(因为他们在创建帐户时指定)
  • 电子邮件验证
  • 许多功能仅由特定代码使用。例如。获取用于 key 派生的用户“salt”。
  • 还有一堆...

我想我可以做一些事情,比如拥有一个继承 User 的 PasswordChanger 类,并实现密码更改功能。所以它看起来像:

$proper = $user->getProperName();
...
$passChanger = $user->getPasswordChanger();
$result = $passChanger->changePassword($oldPass, $newPass);
...
$userLockout = $user->getUserLockout();
$result = $userLockout->isUserLockedOut();
...
$userEV = $user->getEmailValidation();
$result = $userEV->tryValidateEmail($token);
...

这是迄今为止我提出的最佳解决方案。它让我可以将相关功能拆分到它自己的文件中,并且不必传递用户名。但这看起来真的很奇怪——我以前从未见过这样的代码。它强制父类(super class)了解其所有子类,这是糟糕的设计。有什么想法吗?

编辑:另一种避免继承的方法是拥有一个有一个用户的PasswordChanger。喜欢:

$passChanger = new PasswordChanger($user);
$passChanger->changePassword($old, $new); // uses $user->getUsername() 
...
$emailValidator = new EmailValdiator($user);
$emailValidator->tryValidate($token);

“PasswordChanger 有一个用户”与“PasswordChanger 是一个用户”。前者其实很有道理,所以我更喜欢这种方式。

最佳答案

好吧,您已经有了一个良好的开端,而且您提出了正确的问题。虽然没有单一的答案。设计是一门艺术而不是一门科学。听起来您确实在尝试重新设计而不是重构。如果您开始重构您的代码时,您可能会发现它更容易,只是对您的设计可能结束的地方有一个松散的想法(重构的一个非常好的资源是book by Michael Feathers。随着您重构越来越多您应该会发现设计是从黑暗中浮现出来的!而且通常这种设计并不是您开始时所认为的最终结果。

哦,顺便说一句,继承是 OO 最常被过度使用的方面之一。如果您正在考虑继承,请停下来再想一想。如果您仍然认为需要继承,请停下来再想一想。如果您仍然认为您需要继承,那么您可能确实...

关于php - 重构困境 : User Account Functionality in PHP,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9352471/

有关php - 重构困境 : User Account Functionality in PHP的更多相关文章

  1. ruby-on-rails - 如何重构 "shared"方法? - 2

    我正在使用RubyonRails3.2.2,我想从我的模型/类中“提取”一些方法。也就是说,在不止一个类/模型中,我有一些方法(注意:方法与用户授权相关,并被命名为“CRUD方式”),这些方法实际上是相同的;所以我认为DRY方法是将这些方法放在“共享”模块或类似的东西中。实现该目标的常见且正确的方法是什么?例如,我应该将“共享”代码放在哪里(在哪些目录和文件中)?如何在我的类/模型中包含提到的方法?你有什么建议?注意:我正在寻找“RubyonRails制作东西的方式”。 最佳答案 一种流行的方法是使用ActiveSupport关注点

  2. ruby-on-rails - 在 haml View 中重构条件 - 2

    除了可访问性标准不鼓励使用这一事实指向当前页面的链接,我应该怎么做重构以下View代码?#navigation%ul.tabbed-ifcurrent_page?(new_profile_path)%li{:class=>"current_page_item"}=link_tot("new_profile"),new_profile_path-else%li=link_tot("new_profile"),new_profile_path-ifcurrent_page?(profiles_path)%li{:class=>"current_page_item"}=link_tot("p

  3. ruby - 需要重构为新的 Ruby 1.9 哈希语法 - 2

    这个问题在这里已经有了答案:HashsyntaxinRuby[duplicate](1个回答)关闭5年前。我有一个Recipe,其中包含以下未通过lint测试的代码:service'apache'dosupports:status=>true,:restart=>true,:reload=>trueend失败并出现错误:UsethenewRuby1.9hashsyntax.supports:status=>true,:restart=>true,:reload=>true不确定新语法是什么样的...有人可以帮忙吗?

  4. ruby - 重构条件变量赋值 - 2

    我正在做一个项目。目前我有一个相当大的条件语句,它根据一些输入参数为变量赋值。所以,我有这样的东西。ifsomeconditionx=somevalueelsifanotherconditionx=adifferentvalue...重构它的最佳方法是什么?我希望我最终会得到类似的东西x=somevalueifsomecondition||anothervalueifanothercondition这种事情有规律吗? 最佳答案 只需将赋值放在if之外即可。x=ifsomeconditionsomevalueelsifanotherc

  5. ruby-on-rails - 这个 C 和 PHP 程序员如何学习 Ruby 和 Rails? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我来自C、php和bash背景,很容易学习,因为它们都有相同的C结构,我可以将其与我已经知道的联系起来。然后2年前我学了Python并且学得很好,Python对我来说比Ruby更容易学。然后从去年开始,我一直在尝试学习Ruby,然后是Rails,我承认,直到现在我还是学不会,讽刺的是那些打着简单易学的烙印,但是对于我这样一个老练的程序员来说,我只是无法将它

  6. ruby - 重构 Ruby : Converting string array to int array - 2

    我正在重构一个西洋跳棋程序,我正在尝试将玩家移动请求(例如以“3、3、5、5”的形式)处理到一个int数组中。我有以下方法,但感觉不像我所知道的那样像Ruby:deftranslate_move_request_to_coordinates(move_request)return_array=[]coords_array=move_request.chomp.split(',')coords_array.each_with_indexdo|i,x|return_array[x]=i.to_iendreturn_arrayend我用它进行了以下RSpec测试。it"translatesa

  7. ruby - 如何重构这个 6 行方法以使其更具可读性? - 2

    我正试图在这里清理这个非常丑陋的方法,它迫切需要重构,但我不确定哪种结构最能做到这一点(即case语句,或者只是一个精心格式化的ifthen语句)乍一看,这似乎是一个理想的放置case语句的地方,带有一些放置得很好的when,但我的理解是case语句只能用于单个变量,而不是两个变量,以及使用散列或数组尝试这些语句的irb的各种摆弄在这里也没有太多说明。你会怎么做?在检查这样的多个bool值时,Ruby中是否有任何常见的技巧来避免这样的代码?defhas_just_one_kind_of_thing?(item,controller)if(controller=='foos'&&item

  8. ruby-on-rails - Capistrano:deploy.rb 文件重构 - 2

    我的deploy.rb中有以下代码namespace:appdodesc"copiestheconfigurationfrilefrom~/shared/config/*.ymlto~/config"task:copy_config_files,:roles=>:appdorun"cp-fv#{deploy_to}/shared/config/hoptoad.rb#{release_path}/config/initializers"run"cp-fv#{deploy_to}/shared/config/app_config.yml#{release_path}/config/app_

  9. ruby - Rubocop 保护子句困境 - 不必要 if else VS 行太长保护子句 - 2

    我有一段代码,其中有一个带有保护子句的raise语句:defvalidate_indexindex#ChangetoSizeErrorraiseArgumentError,"Sizeofindex(#{index.size})doesnotmatches"\"sizeofvector(#{size})"ifsize!=index.sizeend在这一点上,rubocop给出了罪行:Style/MultilineIfModifier:Favoranormalif-statementoveramodifierclauseinamultilinestatement.我将我的代码修改为正常if

  10. ruby-on-rails - 你如何说服你的经理你的项目需要大量重构? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭8年前。Improvethisquestion我作为承包商加入了一个Rails项目。该项目已经进行了一年多。代码由大约10名不同的开发人员编写,其中大多数也是承包商。他们有不同的代码风格。其中一些来自Java。该代码在metric_fu方面得分很低。许多函数非常长(100-300行)。有些函数有大量的逻辑分支、循环和递归。每个请求都会生成大量的sql查询。性能很差。许多过时的代码从未使用过但从未有机会被清理。核心架构明显错误或设计过度

随机推荐