php - not - Cómo evitar isset() y empty()
php if(! isset (11)
¿Qué hay de usar el operador @? p.ej:
if(@$foo) { /* do something */ }
Puede decir que esto es malo porque no tiene control sobre lo que sucede "dentro" de $ foo (si fue una llamada a función que contiene un error de PHP por ejemplo) pero si solo usa esta técnica para variables, esto es equivalente a:
if(isset($foo) && $foo) { /* ... */ }
Tengo varias aplicaciones anteriores que lanzan una gran cantidad de mensajes "xyz no está definido" y "offset indefinido" cuando se ejecuta en el nivel de error E_NOTICE, porque la existencia de variables no se verifica explícitamente mediante isset()
y consortes.
Estoy considerando trabajar a través de ellos para hacerlos compatibles con E_NOTICE, ya que los avisos sobre variables faltantes o compensaciones pueden salvar vidas, puede haber algunas mejoras menores en el rendimiento y, en general, es la manera más limpia.
Sin embargo, no me gusta lo que inflige cientos de isset()
empty()
y array_key_exists()
s a mi código. Se hincha, se vuelve menos legible, sin ganar nada en términos de valor o significado.
¿Cómo puedo estructurar mi código sin un exceso de comprobaciones variables, al mismo tiempo que soy compatible con E_NOTICE?
Bienvenido a Null coalescente operador:
$field = $_GET[''field''] ?? null;
PHP dice:
El operador coalescente nulo (??) se ha agregado como azúcar sintáctico para el caso común de necesitar usar un ternario junto con isset (). Devuelve su primer operando si existe y no es NULL; de lo contrario, devuelve su segundo operando.
Creo que una de las mejores maneras de lidiar con este problema es accediendo a los valores de las matrices GET y POST (COOKIE, SESSION, etc.) a través de una clase.
Cree una clase para cada una de esas matrices y declare los métodos __get
y __set
( overloading ). __get
acepta un argumento que será el nombre de un valor. Este método debe verificar este valor en la matriz global correspondiente ya sea usando isset()
o empty()
y devuelva el valor si existe o null
(o algún otro valor predeterminado) de lo contrario.
Después de eso, puede acceder con seguridad a los valores de la matriz de esta manera: $POST->username
y realizar cualquier validación si es necesario sin utilizar ningún isset()
empty()
s. Si el username
no existe en la matriz global correspondiente, se devolverá null
, por lo que no se generarán advertencias o avisos.
El software no funciona mágicamente por la gracia de Dios, si estás esperando algo que falta, necesitas manejarlo adecuadamente. si lo ignora, probablemente esté creando agujeros de seguridad en sus aplicaciones. en lenguajes estáticos acceder a una variable no definida simplemente no es posible, no simplemente compilará o bloqueará su aplicación si es nula. además, hace que tu aplicación no pueda ser mantenida y te volverás loco cuando suceden cosas inesperadas. el rigor del lenguaje es una obligación y php, por diseño, está equivocado en muchos aspectos. Te hará un mal programador si no estás enterado.
Estoy aqui contigo. Pero los diseñadores de PHP han cometido errores mucho peores que eso. Además de definir la función personalizada para cualquier lectura de valor, no hay forma de evitarlo.
No estoy seguro de cuál es su definición de legibilidad, pero el uso adecuado de los bloques empty (), isset () y try / throw / catch es muy importante para todo el proceso. Si su E_NOTICE proviene de $ _GET o $ _POST, entonces deben verificarse con empty () junto con todas las demás comprobaciones de seguridad para que esos datos deban pasar. Si proviene de feeds o bibliotecas externas, debe estar envuelto en try / catch. Si proviene de la base de datos, se debe marcar $ db_num_rows () o su equivalente. Si proviene de variables internas, deben inicializarse correctamente. A menudo, este tipo de avisos provienen de la asignación de una nueva variable al retorno de una función que devuelve FALSO en caso de falla, y deben ser envueltos en una prueba que, en caso de falla, puede asignar a la variable un valor predeterminado aceptable. que el código puede manejar, o lanzar una excepción que el código puede manejar. Estas cosas alargan el código, agregan bloques adicionales y agregan pruebas adicionales, pero no estoy de acuerdo con usted en que creo que definitivamente agregan valor extra.
No me importa usar array_key_exists()
, de hecho prefiero usar esta función específica en lugar de confiar en las funciones de hack que pueden cambiar su comportamiento en el futuro como (golpeado para evitar susceptibilities ). empty
y isset
Sin embargo, utilizo una función simple que resulta útil en esto, y algunas otras situaciones al tratar con índices de matriz :
function Value($array, $key, $default = false)
{
if (is_array($array) === true)
{
settype($key, ''array'');
foreach ($key as $value)
{
if (array_key_exists($value, $array) === false)
{
return $default;
}
$array = $array[$value];
}
return $array;
}
return $default;
}
Digamos que tienes las siguientes matrices:
$arr1 = array
(
''xyz'' => ''value''
);
$arr2 = array
(
''x'' => array
(
''y'' => array
(
''z'' => ''value'',
),
),
);
¿Cómo se obtiene el "valor" de las matrices? Sencillo:
Value($arr1, ''xyz'', ''returns this if the index does not exist'');
Value($arr2, array(''x'', ''y'', ''z''), ''returns this if the index does not exist'');
Ya tenemos cubiertas uni y multidimensionales, ¿qué más podemos hacer?
Tome la siguiente pieza de código, por ejemplo:
$url = ''https://.com/questions/1960509'';
$domain = parse_url($url);
if (is_array($domain) === true)
{
if (array_key_exists(''host'', $domain) === true)
{
$domain = $domain[''host''];
}
else
{
$domain = ''N/A'';
}
}
else
{
$domain = ''N/A'';
}
Bastante aburrido ¿no? Aquí hay otro enfoque que usa la función Value()
:
$url = ''https://.com/questions/1960509'';
$domain = Value(parse_url($url), ''host'', ''N/A'');
Como ejemplo adicional, tome la función RealIP()
para una prueba:
$ip = Value($_SERVER, ''HTTP_CLIENT_IP'', Value($_SERVER, ''HTTP_X_FORWARDED_FOR'', Value($_SERVER, ''REMOTE_ADDR'')));
Limpio, ¿eh? ;)
Para los interesados, he ampliado este tema en un pequeño artículo, que proporciona la siguiente información en una forma algo mejor estructurada: La guía definitiva para el isset de PHP Y vacía
En mi humilde opinión, debe pensar no solo en hacer que la aplicación sea "E_NOTICE compatible", sino en reestructurar todo. Tener cientos de puntos en su código que regularmente intentan usar variables inexistentes suena como un programa bastante mal estructurado. Intentar acceder a variables inexistentes nunca debería ocurrir, otros idiomas se resisten a esto en tiempo de compilación. El hecho de que PHP te permita hacerlo no significa que debas hacerlo.
Estas advertencias están ahí para ayudarte , no para molestarte. Si recibes una advertencia "¡Estás intentando trabajar con algo que no existe!" , tu reacción debería ser "Vaya, mi mal, déjame arreglar eso CUANTO ANTES". ¿De qué otra manera vas a decir la diferencia entre "variables que funcionan muy bien indefinidas" y código honestamente incorrecto que puede conducir a errores graves ? Esta es también la razón por la que siempre, siempre , se desarrolla con informes de errores pasados a 11 y sigue tapando su código hasta que no se emita un solo NOTICE
. La desactivación de los informes de errores solo se aplica a entornos de producción, para evitar filtraciones de información y proporcionar una mejor experiencia de usuario, incluso frente al código defectuoso.
Elaborar:
Siempre necesitará isset
o empty
en algún lugar de su código, la única forma de reducir su aparición es inicializar sus variables correctamente. Dependiendo de la situación, hay diferentes formas de hacerlo:
Argumentos de función:
function foo ($bar, $baz = null) { ... }
No es necesario verificar si $bar
o $baz
están configurados dentro de la función porque solo los configura, todo lo que necesita preocuparse es si su valor se evalúa como true
o false
(o lo que sea).
Variables regulares en cualquier lugar:
$foo = null;
$bar = $baz = ''default value'';
Inicialice sus variables en la parte superior de un bloque de código en el que las va a usar. Esto resuelve el problema de !isset
, garantiza que sus variables siempre tengan un valor predeterminado conocido, le da al lector una idea de en qué funcionará el siguiente código y, por lo tanto, también sirve como una especie de auto-documentación.
Arrays:
$defaults = array(''foo'' => false, ''bar'' => true, ''baz'' => ''default value'');
$values = array_merge($defaults, $incoming_array);
Lo mismo que arriba, está inicializando la matriz con valores predeterminados y los sobrescribe con valores reales.
En los casos restantes, digamos una plantilla en la que está generando valores que un controlador puede o no establecer, solo tendrá que verificar:
<table>
<?php if (!empty($foo) && is_array($foo)) : ?>
<?php foreach ($foo as $bar) : ?>
<tr>...</tr>
<?php endforeach; ?>
<?php else : ?>
<tr><td>No Foo!</td></tr>
<?php endif; ?>
</table>
Si te encuentras regularmente usando array_key_exists
, debes evaluar para qué lo estás usando. La única vez que hace una diferencia es aquí:
$array = array(''key'' => null);
isset($array[''key'']); // false
array_key_exists(''key'', $array); // true
Sin embargo, como se indicó anteriormente, si está inicializando adecuadamente sus variables, no necesita verificar si la clave existe o no, porque sabe que sí lo hace. Si obtienes la matriz de una fuente externa, el valor probablemente no sea null
sino ''''
, 0
, ''0''
, false
o algo así, es decir, un valor que puedes evaluar con isset
o empty
, dependiendo de tu intención. Si regularmente establece una clave de matriz como null
y quiere que signifique algo menos false
, es decir, si en el ejemplo anterior los resultados diferentes de isset
y array_key_exists
hacen una diferencia en la lógica de su programa, debería preguntarse por qué. La mera existencia de una variable no debería ser importante, solo su valor debería ser una consecuencia. Si la clave es una bandera de true
/ false
, entonces use true
o false
, no null
. La única excepción a esto serían las bibliotecas de terceros que quieren que null
signifique algo, pero como null
es tan difícil de detectar en PHP, aún no he encontrado ninguna biblioteca que lo haga.
Realiza una función que devuelve false
si no se establece y, si se especifica, false
si está vacío. Si es válido, devuelve la variable. Puede agregar más opciones como se ve en el siguiente código:
<?php
function isset_globals($method, $name, $option = "") {
if (isset($method[$name])) { // Check if such a variable
if ($option === "empty" && empty($method[$name])) { return false; } // Check if empty
if ($option === "stringLength" && strlen($method[$name])) { return strlen($method[$name]); } // Check length of string -- used when checking length of textareas
return ($method[$name]);
} else { return false; }
}
if (!isset_globals("$_post", "input_name", "empty")) {
echo "invalid";
} else {
/* You are safe to access the variable without worrying about errors! */
echo "you uploaded: " . $_POST["input_name"];
}
?>
Solo escribe una función para eso. Algo como:
function get_string($array, $index, $default = null) {
if (isset($array[$index]) && strlen($value = trim($array[$index])) > 0) {
return get_magic_quotes_gpc() ? stripslashes($value) : $value;
} else {
return $default;
}
}
que puedes usar como
$username = get_string($_POST, ''username'');
Haga lo mismo para cosas triviales como get_number()
, get_boolean()
, get_array()
y así sucesivamente.
Yo uso estas funciones
function load(&$var) { return isset($var) ? $var : null; }
function POST($var) { return isset($_POST[$var]) ? $_POST[$var] : null; }
Ejemplos
$y = load($x); // null, no notice
// this attitude is both readable and comfortable
if($login=POST("login")) // really =, not ==
if($pass=POST("pass"))
if($login=="Admin" && $pass==...) {
// login and pass are not empty, login is "Admin" and pass is ...
$authorized = true;
...
}