3

我想为 and 创建一个包装器SessionRequest这样我就不必直接访问 PHP 超全局变量。我意识到,如果我为超全局变量创建一个包装器并使用它们,那么对我的应用程序进行单元测试会更容易,因为可以模拟包装器类。

在尝试创建我的包装类时,我研究了一些示例包装类。其中一些在初始化时将超全局存储为类属性:

class Session
{
    protected $vars;

    public function __construct()
    {
        session_start();

        // POINT OF INTEREST
        // Store the superglobal as a class property
        $this->vars = $_SESSION;
    }    

    public function get($index)
    {
        // POINT OF INTEREST
        // Accesses the class property instead of the superglobal
        return $this->vars[$index];
    }

    public function write($index, $value)
    {
        // Writes both class property and session variable
        $this->vars[$index] = $value;
        $_SESSION[$index] = $value;
    }
}

我的问题:有什么特别的原因为什么在创建包装类时我们将超全局存储为类的属性而不是直接访问它们?将上面的代码与此代码进行对比:

class Session
{
    public function __construct()
    {
        session_start();
    }

    public function get($index)
    {
        // Accesses the superglobal directly
        return $_SESSION[$index];
    }

    public function write($index, $value)
    {
        // Accesses the superglobal directly
        $_SESSION[$index] = $value;
    }
}

IMO,既然包装类无论如何都会被嘲笑,为什么还要将超全局变量存储为类属性呢?有这么多人这样做的特殊原因吗?我应该将超全局变量作为属性存储在它们的包装器中而不是直接访问它吗?

感谢您的任何意见。

4

2 回答 2

5

Session 是一个非常具体的案例。但是您问是否有任何理由包装超级全局变量。以下是一些可能的原因(不按顺序,也不完整):

  1. 减少代码对全局状态的依赖,从而更容易测试。您可以测试依赖于全局状态的代码。但它比测试被告知其状态的代码更难也更脆弱。

  2. 为了使代码更加灵活,因为您可以伪造请求和子请求来做一些在真正的全局状态下不可能完成的有趣事情。

  3. 使代码更具可移植性。通过将其包装在包装器中,您可以在一个中心位置处理依赖于平台的事情,例如去除引号、处理字符集转换等。这可以更轻松地处理平台或多个平台之间的转换。

  4. 对变量实施额外的约束。由于 $_SESSION 允许您在其内部设置您想要的任何内容,因此您可能会遇到一个不可序列化的状态,这可能会导致您出现问题。使用包装器,您可以在一个集中点检查状态以确定它是否匹配必要的约束。

  5. 使您的代码更具可读性。当然,如果您在方法中访问 $_POST,几乎每个 php 开发人员都知道您在做什么。但他们是否需要了解实施细节?还是$request->getFromPostData('foo');更冗长?

  6. 为了使您的代码更易于调试,因为您可以在请求类中设置断点并立即找到所有访问请求变量的事件(只要您从不直接访问它们)。

  7. 让你的类的依赖更容易理解。如果我给你一个使用超级全局变量的类的 API,你无法判断该类是否访问了它,因此无法判断该类需要操作什么。但是如果您需要注入一个请求类,您可以一眼看出该类实际上确实需要请求中的某些内容来操作。因此提高了可读性并更多地阐明了您的 API。

现实中还有更多的原因,但这些都是我能想到的。

于 2011-04-26T20:36:33.170 回答
3

我不认为有什么重要的原因,也许只是如果你改变你所指的超全局你不必在你的类的整个代码中替换它,而只是在构造函数中。

从这个角度来看,我发现write您提供的第一个实现的方法不是很明智,正如您所说,它同时写入类属性和会话变量。

然而,所有这些似乎都有些矫枉过正(并且想得太多)。保持简单,做对你有用的事情。

于 2011-04-26T20:06:20.950 回答