¿Violan $ _POST, $ _GET, etc., el principio de encapsulación?

9

El uso de globales hace que su código sea difícil de probar, por lo que es más propenso a errores, no es seguro e impredecible. Es por eso que pasamos las variables que queremos dentro de una función / objeto. Entonces mi pregunta es simple:

¿Violan $ _POST, $ _GET, etc., el principio de encapsulación ?

Estoy pensando que, para retener el control de esas variables de una manera OO, una solución ideal sería agregar algunas líneas como esta al 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);

No he visto esto en ningún lado, ni siquiera un tutorial ni recomendación. Además, podemos ver claramente cómo el código anterior es mucho más fácil de probar que uno que incluye $Person = new Person($DB, $_GET['id']);o incluso (lo feo), $Person = new Person($DB);ya que puede usar un $getobjeto simulado .

¿El código anterior está en la dirección correcta o me falta algo?

EDITAR: Después de un poco de investigación ( Zend framework y Cake PHP ) como sugirió Alexander Kuzmin, parece ser lo correcto. Probablemente sean demasiado grandes para que yo pueda cavar en el código ATM, pero lo tendré en cuenta.

Francisco Presencia
fuente
1
Encapsular siempre me pareció tonto adherirme como un "principio". Es solo una característica; o un idioma lo tiene o no.
Ignacio Vazquez-Abrams
No soy nativo, así que no estaba seguro de cómo llamarlo y terminé escribiendo principio . Siéntase libre de editar el título / texto si ve que podría tener una mejor redacción.
Francisco Presencia
66
Esto es inteligente y también la forma en que la mayoría de los marcos PHP lo resuelven. Así que sí, creo que estás en algo.
Alexander Kuzmin el
¡Estaba investigando allí, @AlexanderKuzmin! Parece ser el mejor, actualizado.
Francisco Presencia
¿Puedo preguntar por qué tiene la etiqueta de cierre basada en la opinión ? Si bien la segunda subpregunta estoy de acuerdo en que se basa en la opinión (pero solo para el ejemplo específico), creo que la pregunta principal es válida.
Francisco Presencia

Respuestas:

8

No estoy seguro de por qué se aplica json_decodea $_GET“convertir a un una matriz”; $_GETYa es una matriz.

El uso de los superglobales ( $_GET, $_POSTetc.) es una violación del principio de encapsulación. Pero ha habido una línea trazada donde dejas de encapsular cosas. Solicitar datos es un buen candidato para la encapsulación, pero no se deje engañar por la trampa de intentar encapsular todas las cosas .

La mayoría de los frameworks generalmente envuelven los superglobales de PHP en alguna forma de objeto de solicitud. Hacer esto hace que sea más fácil burlarse de las pruebas, etc. El enfoque más simple sería:

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

Es simple y rudimentario, pero hace el trabajo. También es recomendable filtrar los datos en este punto, para defenderse de las inyecciones de XSS.

Pero está envuelto en un Requestobjeto. El Requestobjeto tiene cuatro matrices, y estas matrices se pueden burlar fácilmente:

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

$request = new Request($get, $post, $session, $cookie);
Frijol Martin
fuente
Estoy tratando de convertirlos en objetos, como se indica en el comentario // Convert the $_GET array to an object. Además, esta respuesta stackoverflow.com/a/1869147 es la razón por la que lo estoy haciendo. Aparte de ese pequeño detalle, muchas gracias por una respuesta tan completa con consejos adicionales, eso es muy similar a lo que pretendía hacer.
Francisco Presencia
3
No convertiría $_GETdatos en un objeto. Las matrices no están sucias. Siento que las personas evitan las matrices porque sienten que "no son POO", al igual que nadie se atrevería a usar un <table>HTML por temor a no ser semántico, incluso con datos tabulares. Toma la $_GETmatriz. ¿Qué sucede si paso datos de matriz desde mi formulario, es decir <input type="checkbox" name="foo[]" />o <select name="bar[]" multiple="multiple">? ¿Los vas a convertir en objetos o los dejarás como están? Simplemente deje la $_GETmatriz como una matriz, según lo previsto.
Martin Bean
También pensé en ese caso con matrices de múltiples niveles, y supuse que los convertiría en subobjetos, pero las suposiciones no son buenas. Lo convertí (sucio hasta ahora) en un objeto para poder modificar el getter y setter, lo que me daría más flexibilidad para, por ejemplo, verificar la inyección de XSS en la salida, pero eso también se puede hacer en el esquema propuesto.
Francisco Presencia
Sí, también puedes dejarlos como matrices multidimensionales. Las matrices no están sucias y no hacen que su código sea "no OOP" si las usa como estructura de datos. No les tengas miedo. Si sus datos no tienen ningún método o propiedades (como me gusta GETy POSTdatos), entonces probablemente no necesite ser un objeto.
Martin Bean
Un pequeño problema / inconveniente ... Preguntaría la decisión de incluir $ _SESSION en el objeto de solicitud, debido al manejo especial de PHP de la superglobal $ _SESSION (necesitaría implementar getters / setters y asegurarse de que la sesión se inicia temprano, etc.) y no es realmente parte de la IMO de "solicitud".
MrWhite
2

Usar superglobales $_{POST,GET,SERVER}o lo que sea que viole la encapsulación.

Este problema crece cuando quiere crear "solicitudes locales" dentro del lado del servidor de su aplicación como lo hacen muchos frameworks hoy en día.

No estoy acostumbrado a trabajar con frameworkds, pero lo que suelo hacer es crear un par de Solicitud / Respuesta al comienzo de mi procesamiento. La solicitud contiene los valores de estos parámetros globales.

Si quiero crear una subrequest del lado del servidor, tengo dos opciones: usar el contexto actual o crear uno completamente nuevo. Entonces, creo que no deberías desarmar estas variables superglobales porque QUIZÁS querrías usarlas nuevamente. Además, por esta razón, no estoy de acuerdo con que los parámetros de solicitud sean singletons.

Al contener solo valores, no referencias a estas superglobales, un cambio en un objeto Request nunca afectará a otro, por lo que se resuelve el problema con el estado global.

Entonces, básicamente, tengo dos opciones:

// 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
fuente
0

POST- y GET-vars se envían al servidor de forma masiva y php tiene que tener sentido. En cierto modo, tiene sentido tenerlos disponibles en todo el mundo, para que el desarrollador pueda elegir dónde procesarlos.

Muchos frameworks (como CakePHP, por ejemplo) leen los Parámetros y luego los colocan en una matriz, objeto o estructura similar. Después de eso, se manejan como cualquier otro dato y se pasan a todos los métodos que los necesitan.

Lars Ebert
fuente
1
¿Quiere decir que funciona de esa manera porque PHP no puede inyectar una variable local en el script principal actual como index.php?
Francisco Presencia
No, pero proporcionar las variables a través de una matriz global brinda más flexibilidad para implementar alguna forma de análisis por parte del desarrollador.
0

La encapsulación es un buen principio cuando existe la posibilidad de que necesite varias instancias de algo. Pero solo hay un conjunto de parámetros para una página web. Si estuvieran en una clase en lugar de variables globales, probablemente serían singletons. No hay una mejora significativa al pasar de las variables globales a las clases singleton, es solo una sintaxis diferente para acceder a ellas. Todavía son objetos intrínsecamente globales, es más engorroso porque tienes que controlar la instancia de clase y pasarla.

Como se accede a estos parámetros con tanta frecuencia, los diseñadores de PHP tomaron la decisión de facilitar su acceso, en lugar de adherirse a principios de diseño rígidos. Es una buena idea hacer que las operaciones más comunes sean convenientes, de lo contrario los programadores lo maldecirán por hacer que vuelvan a escribir lo mismo, siempre.

Barmar
fuente
Si bien estoy de acuerdo con el acceso frecuente a ellos, no estoy de acuerdo If they were in a class instead of global variables, they would probably be singletonsya que los singletons también están en el ámbito global . Solo digo que se elimine por completo ese estado global y se convierta en local, tomando prestada esta idea de The Clean Code Talks - "Global State and Singletons" . Se expresa mi principal preocupación al hacer esta pregunta: pruebas . Desafortunadamente, parece que no leyó toda la pregunta, sino solo el título
Francisco Presencia
1
Mi punto es que, dado que solo hay una conexión de cliente y un conjunto de parámetros, estos son inherentemente globales.
Es una compensación: conveniencia versus estricto cumplimiento de los principios de diseño. Si se deshace de las superglobales, tendrá que pasar $getde una función a otra.