Php 从其他类访问登录用户对象的最佳实践
这是一个关于从另一个类存储和访问对象的最佳实践的问题 我在PHP中使用一个简单的自制MVC范例,该类称为User,它有自己的方法和变量,基本上用作数据库抽象层 该类通过调用Php 从其他类访问登录用户对象的最佳实践,php,mysql,session,pdo,Php,Mysql,Session,Pdo,这是一个关于从另一个类存储和访问对象的最佳实践的问题 我在PHP中使用一个简单的自制MVC范例,该类称为User,它有自己的方法和变量,基本上用作数据库抽象层 该类通过调用newUser($userID)实例化,该类从给定$userID的数据库检索数据,如果没有具有该ID的用户,则引发异常 每个页面都有自己的WebViewController类来管理页面的内容,在某些情况下,页面需要调用$loggedInUser相关函数,如WebViewController->displayUserFriend
new
User($userID)
实例化,该类从给定$userID的数据库检索数据,如果没有具有该ID的用户,则引发异常
每个页面都有自己的WebViewController
类来管理页面的内容,在某些情况下,页面需要调用$loggedInUser
相关函数,如WebViewController->displayUserFriends()
,其外观可能如下:
<?php
class WebViewController extends WVCTemplate
{
// Class vars and methods
// ...
public function displayUserFriends()
{
foreach($loggedInUser->getFriends() as $friend) {
// Do something
// ...
}
}
}
?>
class UserService
{
private $authService;
public function __construct(AuthService $authService)
{
$this->authService = $authService;
}
public function getUserFriends(User $user)
{
//...use DAO / models here...
}
public function getUserFriendsForCurrentUser()
{
$user = $this->authService->getCurrentUser();
if (!$user)
throw new DomainException('Must be logged in to do that.');
return $this->getUserFriends($user);
}
}
是否有一种(符合最佳实践的)方法将LoggedInUser存储为一种全局对象,这样就可以在任何类或
WebViewController
中访问它,而无需在所使用的每个类中实例化它?我认为这是一个意见问题,真的。尽管如此,在这里我将提出两个可行的选择
选择1
…是创建将容纳当前用户的单例:
class SessionHolder
{
private $user;
public static function getCurrentUser()
{
return self::$user;
}
public static function setCurrentUser(User $user)
{
self::$user = $user;
}
}
用法:
//Authentication does following:
SessionHolder::setCurrentUser($user);
//web view controller does following:
SessionHolder::getCurrentUser();
明显的优点是,在任何框架中都很容易将其合并。缺点是使用单例通常不是一个好主意,因为它们使测试代码变得非常困难(您无法测试它们)。跟踪您的依赖关系也很困难。要回答“我的控制器是否依赖于活动用户?”的问题,您需要手动搜索代码
我认为测试部分非常重要,因为你迟早会在工作中遇到TDD(如果你还没有),因此,知道如何处理它的特性是很好的
选择2
使用服务层。我认为这是组织你的项目最好的方法之一。例如,我经常在项目中使用以下结构:
- 控制器-充当服务的代理,从
、\u GET
等收集用户输入\u POST
- 服务——例如,包含业务逻辑——哪些项目应该放入客户的订单中
- 模型/DAO层-包含数据库逻辑,如如何获取数据
-返回当前登录的用户AuthService::getCurrentUser()
-返回任意用户的好友UserService::getUserFriends(User$User)
-返回活动用户的好友UserService::getUserFriendsForCurrentUser()
使用UserService::getUserFriendsForCurrentUser()
AuthService::getCurrentUser()
现在依赖于UserService
AuthService
- 最后,您的控制器可以调用
来获取它们,并在将它们发送到视图层之前选择性地装饰它们$this->userService->getUserFriendsForCurrentUser()
<?php
class WebViewController extends WVCTemplate
{
// Class vars and methods
// ...
public function displayUserFriends()
{
foreach($loggedInUser->getFriends() as $friend) {
// Do something
// ...
}
}
}
?>
class UserService
{
private $authService;
public function __construct(AuthService $authService)
{
$this->authService = $authService;
}
public function getUserFriends(User $user)
{
//...use DAO / models here...
}
public function getUserFriendsForCurrentUser()
{
$user = $this->authService->getCurrentUser();
if (!$user)
throw new DomainException('Must be logged in to do that.');
return $this->getUserFriends($user);
}
}
优点:您的代码是可测试的,而且代码看起来也很干净。只要浏览一下构造函数,依赖关系就很明显了。业务逻辑与控制器很好地分离,控制器就像代理一样
缺点:您需要生成更多的样板代码。它也不是真正的MVC。然而,既然你自己说你使用自制的MVC模式,我认为这种方法也值得一试
作为一个侧节点—正如您所看到的,我们使用构造函数将
AuthService
注入UserService
。我认为值得一提的是:
- 我们没有将singleton
与静态方法一起使用,因为我们想测试我们的AuthService
类。为了测试它,我们可以使用mock,也可以不使用mock。在这种特殊情况下,我们希望模拟AuthService。这样做很简单,只需在测试中实现您的UserService
变体,并使用此存根创建AuthService
,而不是真正的UserService
。如果您希望了解更多关于使代码可测试的良好实践,请参阅更多关于TDD的内容,因为我认为这不在本问题的范围之内AuthService
- 重要的是要知道,您不应该每次需要使用
UserService时都手动构造它的所有依赖项。这就是依赖注入的作用所在——您只需声明您的UserService需要什么,然后使用对象工厂检索其实例。(理想情况下,您只需要在整个项目中调用一次对象工厂,它将在运行时基础上构建整个依赖关系树)。它也在播放
- 解决您的问题最优雅的方法就是使用。由于您可能需要多个控制器中的当前用户,因此最好创建一个
AuthenticationService
(或类似)来提供检查用户是否已登录以及获取当前登录用户的方法,并封装该公共功能。然后,您可以将服务实例注入所有需要它的控制器中
有几个独立的PHP依赖项注入库:
$GLOBALS['CurrentUser']
?是的,我认为全局变量是一种不好的做法。他们是巴