PHP Encapsulation – Do $_POST, $_GET, etc. Violate Encapsulation Principle?

object-orientedPHP

Using globals makes your code hard to test thus more prone to bugs, not secure and unpredictable. That's why we pass the variables we want inside a function/object. So my question is simple:

Do $_POST, $_GET, etc violate the encapsulation principle?

I'm thinking that, to retain control of those variables in an OO way, an ideal solution would be to add some lines like this to the code:

// Convert the $_GET array to an object
$get = json_decode(json_encode($_GET), FALSE);  // stackoverflow.com/a/1869147
// Stop it from being included from anywhere
unset($_GET);

// Small example of what could be done later on
$DB = new PDO(/* ... */);
$Person = new Person($DB, $get->id);

I haven't seen this anywhere, not even a tutorial nor recommendation. Also, we can clearly see how the code above is much easier to be tested than one that includes $Person = new Person($DB, $_GET['id']); or even (the ugly) $Person = new Person($DB); as you can use a mock $get object.

Is the code above in the right direction or am I missing something?

EDIT: After some investigation (Zend framework and Cake PHP) as Alexander Kuzmin suggested, it seems to be the right thing to go. They're probably too big for me to dig into the code ATM, but I'll keep it in mind.

Best Answer

I’m not quite sure why you apply json_decode to $_GET to “convert it to an a array”; $_GET already is an array.

Using the super-globals ($_GET, $_POST etc) is a violation of the encapsulation principle. But there has been to be a line drawn where you stop encapsulating things. Request data is a good candidate for encapsulation, but don’t get sucked down the rabbit hole of trying to encapsulate all the things.

Most frameworks usually wrap PHP’s super-globals into some form of request object. Doing this then makes it easier to mock for tests etc. The simplest approach would be:

<?php
class Request
{
    public $get;
    public $post;
    public $session;
    public $cookie;

    public function __construct($get, $post, $session, $cookie)
    {
        $this->get = $get;
        $this->post = $post;
        $this->session = $session;
        $this->cookie = $cookie;
    }
}

$request = new Request($_GET, $_POST, $_SESSION, $_COOKIE);

It’s simple and rudimentary, but does the job. It’s also advisable to filter the data at this point, to defend against XSS injections.

But it’s wrapped in a Request object. The Request object has four arrays, and these arrays can easily be mocked:

$get = array(
    'foo' => 'bar'
);
$post = array();
$session = array(
    'user' => 1
);
$cookie = array();

$request = new Request($get, $post, $session, $cookie);
Related Topic