PHP面向对象Web应用程序

4
我有一个名为“Layout”的类,用于页面布局,另一个名为“User”的类,用于用户。
每次创建页面时,我都会实例化一个新的Layout。
当用户登录时,会实例化一个新的User。
如何让布局类知道已实例化的用户?我也可以将整个User实例保存在会话变量中。但我认为这不是一个好主意。有什么最佳实践吗?
class User
{
  var $userid;
  var $email;
  var $username;

  function User($user)
  {
     $this->userid = $this->getUid($user);
     $this->email = $this->getEmail($user);
     $this->username = $user;
  }
  function getUid($u)
  {
     ...
  }

  function getEmail($u)
  {
     ...
  }
}

class Layout
{

    var $var1;
    var $var2;
    var $var3;

    function Layout()
    {
        //defaults...
    } 


    function function1()
    {
        echo "something";
    }


   function function2()
   {
        echo "some other stuff";
   }

   function function3()
   {
      echo "something else";
   }

}

例如,在index.php中,我会执行以下操作:

include "user.php"
include "layout.php"

$homelayout = new Layout();
$homelayout->function1();
$homelayout->function2();
$homelayout->function3();

现在假设有人在login.php中登录:

include "layout.php"
include "user.php"

if(userAuthSuccess)
{
    $currentUser = new User($_POST['username']);
}

如何在用户未注销的情况下,从所有php文件中访问$currentUser及其成员变量(例如$currentUser->email等)?

最好的方法是将$currentUser保存在会话(session)中。当用户登录时,将$currentUser存储在会话中,并在需要访问该用户数据时,从会话中检索它。


$_SESSION 不支持对象。 - Dolph
你可以将用户实例作为参数传递给布局构造函数或者作为布局类某些方法的参数... - E.M.
$_SESSION 很好地支持对象,只要在开始会话之前加载对象的类或定义一个 __autoload 函数来查找并包含它们。 - cHao
在这种情况下,哪种做法是最佳实践?将用户实例作为参数传递给布局构造函数,还是将用户对象仅存储在会话中? - Sev
你能给我们展示一些样例代码吗,这样我们就知道你为什么需要它。似乎有更好的方法。 - Galen
5个回答

1

我认为解决上述问题的最佳方法是采用依赖注入的概念,即编写一个额外的类,将依赖项(在本例中为对象)注入到请求类中。大多数现代开发人员都会遵循使用这种将依赖项注入到应用程序中的技术,因为这将使:

松耦合程序 - 由于依赖关系由第三个类注入,因此无需在程序逻辑中硬编码依赖关系。

可维护代码 - 这是面向对象编程范例最吸引人的特性之一。当涉及到大规模程序时,这一点尤其正确。

内存管理 - 作为开发人员,您可以根据自己的规格要求自由地管理内存。


1
抱歉,我没有意识到这个话题已经超过两年了。无论如何,这可能对其他人有用。 - Bhaskar Pramanik

0

使用注册表模式。没有必要将其设置为单例,每个人都在随意使用这个词。

include "layout.php"
include "user.php"

if(userAuthSuccess)
{
    $data['currentUser'] = new User($_POST['username']);
}

$data['nav'] = new nav('home'); 

$homelayout = new Layout( $data );

现在,$homelayout 可以通过数据数组访问$data(其中包含您放入其中的所有变量)。

在一个用户类(每个会话只有一个用户)或数据库类(假设整个过程中只需要一个连接)的情况下,为什么不建议使用单例类? - Sev
有什么意义吗?你害怕会意外创建多个用户吗? - Galen
那么,为了使用你的方法,我需要一个全局变量来保存用户是否已登录的状态,对吗? - Sev
此外,我需要在每个页面创建一个新的用户。 - Sev
它多了一行代码。同时让其他人阅读你的代码更加易懂。 - Galen

0
将某些东西“全球化”通过将其放入会话变量或cookie中,仅为了全球化而这样做是一个非常不好的习惯,并且会导致紧密耦合的库依赖于在类外设置的任意变量。总的来说,最好远离会话变量,因为还有其他原因。
将变量传递为参数是将任何类中的变量传递的最佳方法。您的Layout类中是否有一个呈现(输出)它的方法?您可能希望向该方法添加$data参数,该参数接受可在布局中使用的关联数组数据。

0

由于每个请求和程序运行只会有一个用户,因此这是将“用户”作为单例类的情况,可以参考此处的描述:

http://php.net/manual/en/language.oop5.patterns.php

这将为其他类提供一种方式,以引用当前用户,而不会访问错误的实例,因为只有一个实例。

免责声明: 是的,我知道单例模式经常被错误地用于错误的目的,有些人倾向于将这个问题归咎于模式本身,而不是那些将其误用于某些糟糕代码的人。 然而,这是单例模式的完美应用案例。


我已经编辑了我的帖子以展示一些代码。假设我将User类设置为单例类...我需要将User的实例传递给其他类的每个实例吗?如果不需要,能否请您展示一些代码来解释一下。 - Sev
如果您的User类是单例模式,您可以使用User::singleton()方法访问它唯一存在的实例,假设该方法名称来自于PHP手册页面。该方法将始终返回User的确切实例,并且不允许任何其他访问方式。 - selfawaresoup

0

我个人会使用注册表类(Singleton)并在其中注册用户,以便布局可以访问。这样,您只需要将注册表的实例传递给布局即可。

User类对于Layout的构建并不是必要的 - 因为它只应关注Layout,所以我不会在构造函数中传递它。

另一种方法是使用控制器来协调视图和模型之间的交互。每当创建新的控制器时,请缓冲其输出。然后,在渲染时,取消缓冲内容并将其分配给视图的属性(或属性数组),然后可以呈现它们。您可能不需要将实际的Model类传递给View/Layout - 只需要它的输出即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接