Should I store superglobals as the wrapper class' property or should I access it directly?
I wanted to create a wrapper for Session
and Request
so that I don't have to access the PHP superglobals directly. I realized that if I create a wrapper for the superglobals and use them, unit testing my application will be easier as the wrapper class can be mocked.
While trying to create my wrapper class, I researched some sample wrapper classes. Some of them stores the superglobal as a class property at initialization:
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;
}
}
My question: is there any particular reason why while creating a wrapper class we store the superglobal as the cl开发者_高级运维ass' property instead of accessing them directly? Contrast the above code with this one:
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, since the wrapper class would be mocked anyway, why bother storing the superglobals as a class property? Is there a particular reason why so many people do this? Should I store the superglobals as a property in their wrapper instead of accessing it directly?
Thanks for any input.
Session is a pretty specific case. But you asked if there was any reason to wrap super-globals. Here are a few possible reasons (Not in order, nor complete):
To make the code less dependent upon global state and hence easier to test. You can test code that depends on a global state. But it's harder and more fragile than testing code that gets told its state.
To make code more flexible since you can then fake requests and sub-requests to do interesting things that wouldn't be possible with a true global state.
To make the code more portable. By wrapping it in a wrapper, you can handle platform dependent things such as stripping quotes, handling character set conversions, etc in a central location. This can make it easier to handle a shift between platforms or multiple platforms.
To enforce additional constraints upon the variable. Since $_SESSION allows you to set anything you want inside itself, you can wind up with a non-serializable state which could cause you problem. With a wrapper, you have one centralized point where you can check the state to determine if it matches the constraints necessary.
To make your code more readable. Sure, just about every php developer knows what you're doing if you access $_POST in a method. But do they need to know about that implementation detail? Or is
$request->getFromPostData('foo');
more verbose?To make your code easier to debug since you can set a breakpoint in the request class and immediately find all occurrences of accessing request variables (as long as you never access them directly).
To make your class's dependencies easier to understand. If I gave you an API for a class that used the super globals, you can't tell if that class accessed it, and hence exactly what the class needs to operate. But if you require a request class to be injected, you could tell at a quick glance that the class actually does need something from the request to operate. Hence improving readability and clarifying your API more.
There are more reasons in reality, but those are the ones I can think of off the top of my head.
I don't think there's some important reason, maybe it's just that if you change the superglobal you're referring to afterwards, you haven't got to replace it in the whole code of your class, but just in the constructor.
From this point of view, I find not very sensible the write
method of the first implementation you provided, that writes both class property and session variable, as you remarked.
All of this seems a bit overkill (and overthink), however. Just keep simple and do things that are useful to you.
精彩评论