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

PHP MVC最佳实践-将会话变量从控制器传递到模型类或直接在模型中访问,php,model-view-controller,design-patterns,session,Php,Model View Controller,Design Patterns,Session,我们的开发团队正在讨论一般最佳实践: 最好是直接从模型类中的函数访问会话变量,还是将会话变量作为参数从控制器传递给模型类中的函数。请看以下两个示例: 直接从模型类访问要在查询中使用的会话变量: class MyModel { public function getUserPrefs($userID) { $this->query("SELECT * FROM my_table WHERE id=$_SESSION['userID']"); } } 或者将会

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

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

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");
    }
}
将其从控制器传递到模型的理由是,所有引用的数据都来自一个入口点,即控制器


什么被认为是更好的实践?

第二个版本(将$\u SESSION['userId']作为参数传递给方法)产生了一个更解耦的类,因此更灵活。继续吧。

请记住,“会话”只是另一种模式。然而,第一种方法是不可接受的——如果您想获取另一个用户的首选项,只是为了将它们与其他东西进行比较,该怎么办?使用第二种方法。

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

function find_by_id() {
  // SELECT * FROM Users WHERE user_id = $_SESSION['user_id'];
}
但是,如果您现在需要使用用户查找功能构建管理功能,该怎么办?您的模型已硬编码为使用会话的用户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
}

您还应该考虑使用SigelTon类来限制用户的数据库负载。创建名为CurrentUser(例如)的非更改实例类,如下所示:

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

我同意Seth re的观点。“还应该考虑使用SigeltTepe类来限制数据库加载。创建一个名为CurrutUsor的非更改实例类。

在我的伪MVC应用程序中,类用户(指当前用户)具有会话、获取用户信息、角色等的方法,类成员(指任何给定用户)具有注册新用户、获取/更新其属性等的方法,但与会话无关,例如。而且,这是一个单例场景,所以当前用户是静态的,不需要和数据库进行太多交互

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


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

是的,因此
controller
是决定从模型中获取什么并发送到视图的主要对象+1+1控制器被称为控制器是有原因的。它的工作是控制输入(在这种情况下是一个会话变量)并将其传递给适当的处理程序(视图、模型、库等)。另外一个注意事项是,我认为您应该使用一个名为“session”的“包装器”类,它包含获取/设置会话变量的所有功能。通过在一个文件/类中更改memcache,您可以轻松地切换到使用memcache之类的东西?您仍然必须在页面加载时创建此对象,对吗?它不会改变它与DB交互的频率。singleton的优点是您不必每次都构造它。因此,它适用于只需在应用程序中创建一次的对象,例如CurrentUser。但是,如果要列出许多用户,这是行不通的,因为您必须为每个用户创建类的实例。@使用缓存依赖项注入器容器的mvblfst可能更好,谢谢您的深入解释
class CurrentUser {

  private static $user;

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

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

}