$ _POST, $ _GET, etc violam o princípio do encapsulamento?

9

O uso de globais torna seu código difícil de testar, portanto, mais propenso a erros, não seguro e imprevisível. É por isso que passamos as variáveis ​​que queremos dentro de uma função / objeto. Então, minha pergunta é simples:

$ _POST, $ _GET, etc violam o princípio do encapsulamento ?

Estou pensando que, para manter o controle dessas variáveis ​​de uma maneira OO, uma solução ideal seria adicionar algumas linhas como esta ao código:

// 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);

Eu não vi isso em lugar nenhum, nem mesmo um tutorial ou recomendação. Além disso, podemos ver claramente como o código acima é muito mais fácil de ser testado do que aquele que inclui $Person = new Person($DB, $_GET['id']);ou mesmo (o feio), $Person = new Person($DB);pois você pode usar um $getobjeto simulado .

O código acima está na direção certa ou estou faltando alguma coisa?

EDIT: Depois de alguma investigação ( framework Zend e Cake PHP ), como Alexander Kuzmin sugeriu, parece ser a coisa certa a seguir. Eles provavelmente são grandes demais para eu digitar o código do caixa eletrônico, mas vou lembrar disso.

Francisco Presencia
fonte
1
Para mim, o encapsulamento sempre me pareceu bobo como um "princípio". É apenas um recurso; ou um idioma possui ou não.
Ignacio Vazquez-Abrams
Eu não sou nativo, então não tinha certeza de como chamá-lo e acabei escrevendo o princípio . Sinta-se à vontade para editar o título / texto, se achar que ele pode ter uma redação melhor.
Francisco Presencia
6
Isso é inteligente e também é a maneira que a maioria das estruturas PHP resolve. Então sim, acho que você gosta de algo.
Alexander Kuzmin
Eu estava apenas investigando lá, @AlexanderKuzmin! Parece ser o melhor, atualizado.
Francisco Presencia
Posso perguntar por que ele possui a marca de fechamento baseada em opinião ? Enquanto a segunda sub-questão, eu concordo, é baseada em opiniões (mas apenas no exemplo específico), acho que a questão principal é válida.
Francisco Presencia

Respostas:

8

Eu não estou muito certo porque você aplica json_decodepara $_GETa “convertê-lo em um uma matriz”; $_GETé uma matriz.

O uso das super globais ( $_GET, $_POSTetc) é uma violação do princípio do encapsulamento. Mas deve haver uma linha traçada onde você para de encapsular as coisas. Os dados de solicitação são um bom candidato ao encapsulamento, mas não seja sugado pelo buraco do coelho ao tentar encapsular todas as coisas .

A maioria das estruturas geralmente envolve as super globais do PHP em alguma forma de objeto de solicitação. Fazer isso facilita a simulação de testes, etc. A abordagem mais simples seria:

<?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);

É simples e rudimentar, mas faz o trabalho. Também é aconselhável filtrar os dados neste momento, para se defender contra injeções de XSS.

Mas está envolto em um Requestobjeto. O Requestobjeto possui quatro matrizes e essas matrizes podem ser facilmente zombadas:

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

$request = new Request($get, $post, $session, $cookie);
Martin Bean
fonte
Estou tentando convertê-los em objetos, conforme declarado no comentário // Convert the $_GET array to an object. Além disso, esta resposta stackoverflow.com/a/1869147 é o motivo pelo qual estou fazendo isso. Com esses pequenos detalhes, muito obrigado por uma resposta tão completa com dicas extras, que é muito semelhante ao que eu pretendia fazer.
Francisco Presencia
3
Eu não converteria $_GETdados em um objeto. Matrizes não estão sujas. Sinto que as pessoas evitam as matrizes porque sentem que "não são OOP", assim como ninguém ousaria usar um <table>em HTML por medo de ser semântico, mesmo com dados tabulares. Pegue a $_GETmatriz. O que acontece se eu passar dados de matriz do meu formulário, <input type="checkbox" name="foo[]" />ou seja, ou <select name="bar[]" multiple="multiple">? Você vai convertê-los em objetos ou deixá-los como estão? Apenas deixe a $_GETmatriz como uma matriz, como pretendido.
Martin Feijão
Pensei também nesse caso com matrizes de vários níveis e presumi que isso os tornaria subobjetos, mas as suposições não são boas. Eu o convertei (sujo até agora) em um objeto para poder modificar o getter e o setter, o que me daria mais flexibilidade para, por exemplo, verificar a injeção de XSS na saída, mas isso também pode ser feito no esquema proposto.
Francisco Presencia 12/11
Sim, você também pode deixá-los como matrizes multidimensionais. As matrizes não estão sujas e não tornam seu código "não OOP" se você as usar como estrutura de dados. Não tenha medo deles. Se os dados não tem nenhum métodos ou propriedades (como GETe POSTdados), então provavelmente não precisa ser um objeto.
Martin Bean
Problema secundário / niggle ... Gostaria de consultar a decisão de incluir o $ _SESSION no objeto de solicitação, devido ao tratamento especial do PHP da superglobal $ _SESSION (você precisaria implementar getters / setters e garantir que o sessão é iniciada mais cedo etc.) e não faz parte da IMO "solicitação".
MrWhite
2

O uso de superglobais $_{POST,GET,SERVER}ou qualquer outra coisa certamente viola o encapsulamento.

Esse problema aumenta quando você deseja criar "solicitações locais" no lado do servidor do aplicativo, como muitas estruturas fazem hoje em dia.

Não estou acostumado a trabalhar com frameworkds, mas o que geralmente faço é criar um par de Solicitação / Resposta no início do meu processamento. A solicitação contém os valores desses parâmetros globais.

Se eu quiser criar uma subconsulta do lado do servidor, tenho duas opções: usar o contexto atual ou criar um totalmente novo. Então, acho que você não deve desmarcar essas variáveis ​​superglobais porque TALVEZ desejaria usá-las novamente. Além disso, por esse motivo, discordo que os parâmetros de solicitação devem ser singletons.

Ao conter apenas valores, e não referências a esses superglobais, uma alteração em um objeto Request nunca afetará outro, portanto, o problema com o estado global é resolvido.

Então, basicamente, eu tenho duas opções:

// Using global context
$request = new Request(array(
    'post' => $_POST,
    'get' => $_GET
));

// or creating a new context

$request = new Request(array(
    'post' => ['someKey' => 'someValue'],
    'get' => ['queryParam' => 'queryValue'],
));
Henrique Barcelos
fonte
0

Os vars POST e GET são enviados para o servidor em um único lote e o php precisa dar sentido a eles. De certa forma, faz sentido tê-los disponíveis globalmente, para que o desenvolvedor possa escolher onde processá-los.

Muitas estruturas (como o CakePHP, por exemplo) leem os Parâmetros e depois as colocam em alguma matriz, objeto ou estrutura semelhante. Depois disso, eles são tratados como quaisquer outros dados e são passados ​​para todos os métodos que precisam deles.

Lars Ebert
fonte
1
Você quer dizer que funciona dessa maneira porque o PHP não pode injetar uma variável local no script principal atual como index.php?
Francisco Presencia 12/11
Não, mas fornecer as variáveis ​​por meio de matriz global oferece mais flexibilidade para implementar alguma forma de análise pelo desenvolvedor.
0

Encapsulamento é um bom princípio quando há uma chance de que você precise de várias instâncias de algo. Mas há apenas um conjunto de parâmetros para uma página da web. Se eles estivessem em uma classe em vez de variáveis ​​globais, provavelmente seriam singletons. Não há melhoria significativa passando de variáveis ​​globais para classes singleton, é apenas uma sintaxe diferente para acessá-las. Eles ainda são objetos inerentemente globais, é apenas mais complicado porque você precisa entender a instância da classe e distribuí-la.

Como esses parâmetros são acessados ​​com tanta frequência, os designers do PHP decidiram torná-los fáceis de acessar, em vez de aderir a rígidos princípios de design. É uma boa idéia tornar as operações mais comuns convenientes, caso contrário os programadores o xingarão por fazê-los redigitar a mesma coisa, sempre.

Barmar
fonte
Embora eu concorde com o acesso frequente a eles, não concordo, If they were in a class instead of global variables, they would probably be singletonspois os singletons também estão no escopo global . Estou apenas dizendo sobre excluir completamente esse estado global e torná-lo local, tomando emprestada essa idéia do The Clean Code Talks - "Estado Global e Singletons" . Expressou minha principal preocupação ao fazer esta pergunta: teste . Infelizmente, parece que você não leu toda a pergunta, mas apenas o título #
Francisco Presencia 12/11/2013
1
Meu argumento é que, como existe apenas uma conexão com o cliente e um conjunto de parâmetros, eles são inerentemente globais.
É uma troca: conveniência versus adesão estrita aos princípios de design. Se você se livrar dos superglobais, precisará passar $getde uma função para outra.