PHP MVC 最佳实践 - 将 Session 变量从控制器传递给模型类或直接在模型中访问

Posted

技术标签:

【中文标题】PHP MVC 最佳实践 - 将 Session 变量从控制器传递给模型类或直接在模型中访问【英文标题】:PHP MVC Best Practice - Pass Session variable to model class from controller or access directly in model 【发布时间】:2011-05-29 00:14:56 【问题描述】:

我们的开发团队正在讨论一般的最佳做法: 是直接从模型类中的函数访问会话变量还是将会话变量从控制器作为参数传递给模型类中的函数更好。看下面两个例子:

直接从模型类访问会话变量以在查询中使用:

class MyModel 
    public function getUserPrefs($userID) 
        $this->query("SELECT * FROM my_table WHERE id=$_SESSION['userID']");
    

或者将会话变量从控制器传递给模型类中的函数作为函数参数:

class MyController 
    public function displayUsers() 
        $this->model->getUserPrefs($_SESSION['userID']);
    


class MyModel 
    public function getUserPrefs($userID) 
        $this->query("SELECT * FROM my_table WHERE id=$userID");
    

将其从控制器传递给模型的原因是,所有引用的数据都来自一个入口点,即控制器。

什么被认为是更好的做法?

【问题讨论】:

【参考方案1】:

第二个版本(将 $_SESSION['userId'] 作为参数传递给方法)产生了一个更加解耦的类,因此更加灵活。随它去吧。

【讨论】:

是的,因此controller 它是决定应该从模型中获取什么并发送到视图的主要对象。 +1 +1 控制器被称为控制器是有原因的。它的工作是控制输入(在这种情况下是会话变量)并将其传递给适当的处理程序(视图、模型、库等)。 另一个注意事项是,我认为您应该使用一个名为“Session”之类的“包装器”类,它体现了获取/设置会话变量的所有功能。这样,您可以通过在一个文件/类中更改它来轻松切换到使用 memcache 之类的东西。【参考方案2】:

您永远不想在模型中包含会话变量。您应该始终将这些变量作为参数传递给模型中的函数。这也使您的代码更具可扩展性和灵活性。考虑一个通过 id 获取用户的模型。您可以编写如下函数:

function find_by_id() 
  // SELECT * FROM Users WHERE user_id = $_SESSION['user_id'];

但是,如果您现在要使用用户查找功能构建管理功能怎么办?您的模型被硬编码为使用会话的 user_id,但您希望能够传递您自己的 id。你会更好:

function find_by_id($id) 
  // SELECT * FROM Users WHERE user_id = $id

在你的控制器中

$user = Model::find_by_id(1);
//or
$user = Model::find_by_id($_SESSION['user_id']);
//etc

不过,在这种情况下,我真的会考虑让您的代码更加灵活:

function find($ids) 
  // this is pseudo code, but you get the idea
  if(is_array($ids))
    $ids = implode(',', $ids); // if an array of ids was passed, implode them with commas
  SELECT * FROM Users WHERE user_id IN ($ids);

这允许您在一个查询中获得多个用户!哪种方式更有效率。那么,在你看来:

foreach($users as $user)
  // iterate over each user and do stuff

您还应该考虑为用户使用单例类来限制数据库负载。创建一个名为 CurrentUser 的不变实例类(例如),例如:

class CurrentUser 

  private static $user;

  // we never instantiate it -its singleton
  private function __construct() 

  public function user() 
    return self::$user;
  


这是一个非常基本的单例类示例,缺少很多东西。如果您想了解更多关于单例类的信息,请发布另一个问题。

【讨论】:

感谢您的深入解释【参考方案3】:

请记住,“会话”只是另一种模型。但是第一种方法是不可接受的——如果您想获取其他用户的偏好只是为了将它们与某些东西进行比较怎么办?使用第二种方法。

【讨论】:

【参考方案4】:

我同意赛斯的观点。 “您还应该考虑为用户使用单例类来限制数据库负载。创建一个名为 CurrentUser 的不变实例类。

在我的伪 MVC 应用程序中,我有类 User(表示当前用户),其中包含用于会话、获取用户信息、角色等的方法,以及类 Member(表示任何给定用户),其中包含用于注册新用户、获取/更新的方法例如,它们的属性等但与会话无关。此外,它是单例场景,因此当前用户是静态的,不需要与数据库进行太多交互。

所以在我的例子中,我的控制器和视图调用用户方法,例如

User::getId()User::getGroups()

【讨论】:

我很困惑为什么单例与数据库的交互较少?您仍然需要在页面加载时创建此对象,对吗? 它不会改变它与数据库交互的频率。单例的优点是您不必每次都 __construct 它。因此它适用于必须在应用程序中只创建一次的对象,例如当前用户。它不适用于制作许多用户的列表,因为您必须为每个用户创建类的实例。 @mvblfst 使用缓存依赖注入器容器可能会更好,

以上是关于PHP MVC 最佳实践 - 将 Session 变量从控制器传递给模型类或直接在模型中访问的主要内容,如果未能解决你的问题,请参考以下文章

PHP MVC 最佳实践与 Doctrine 2

PHP 中的会话超时:最佳实践

如何将消息插入取决于会话值的视图。 ASP.NET MVC。最佳实践

Spring MVC 领域对象处理最佳实践

.NET MVC3 中多页表单的最佳实践/设计

MVC 验证 - 使用服务层保持 DRY - 最佳实践是啥?