Tengo varias aplicaciones antiguas que arrojan muchos mensajes "xyz no está definido" y "desplazamiento indefinido" cuando se ejecutan en el nivel de error E_NOTICE, porque la existencia de variables no se comprueba explícitamente con isset()
y consorts.
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 forma más limpia.
Sin embargo, no me gusta lo que cientos de infligir isset()
empty()
y array_key_exists()
S todavía 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 de variables, y al mismo tiempo ser compatible con E_NOTICE?
fuente
Respuestas:
Para aquellos 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 isset And empty de PHP
En mi humilde opinión, deberías pensar no solo en hacer que la aplicación sea "compatible con E_NOTICE", 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 suceder, otros lenguajes 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 ayudarlo , no para molestarlo. Si recibe una advertencia "¡Está intentando trabajar con algo que no existe!" , tu reacción debería ser "Vaya, mi error, déjame arreglar eso lo antes posible". ¿De qué otra manera va a diferenciar entre "variables que funcionan bien sin definir" y código honestamente incorrecto que puede conducir a errores graves ? Esta es también la razón por la que siempre, siempre , desarrolla con informes de errores en 11 y sigue trabajando en su código hasta que no
NOTICE
se emite un . La desactivación de los informes de errores es solo para entornos de producción, para evitar la fuga de información y proporcionar una mejor experiencia de usuario incluso frente a códigos defectuosos.Elaborar:
Siempre necesitará
isset
oempty
en algún lugar de su código, la única forma de reducir su ocurrencia es inicializar sus variables correctamente. Dependiendo de la situación, hay diferentes formas de hacerlo:Argumentos de la función:
No hay necesidad de comprobar si
$bar
o$baz
se establece dentro de la función, ya que acaba de establecer ellos, todo lo que necesita es preocuparse por si sus evalúa el valor detrue
ufalse
(o cualquier otra cosa).Variables regulares en cualquier lugar:
Inicialice sus variables en la parte superior de un bloque de código en el que las va a usar. Esto resuelve el
!isset
problema, asegura 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.Matrices:
Lo mismo que antes, está inicializando la matriz con valores predeterminados y sobrescribiéndolos con valores reales.
En los casos restantes, digamos una plantilla en la que está generando valores que pueden o no ser establecidos por un controlador, solo tendrá que verificar:
Si lo usa regularmente
array_key_exists
, debe evaluar para qué lo está usando. La única vez que marca la diferencia es aquí:Sin embargo, como se indicó anteriormente, si está inicializando correctamente sus variables, no necesita verificar si la clave existe o no, porque sabe que existe. Si usted está recibiendo la matriz de una fuente externa, el valor más probable es que no sea
null
pero''
,0
,'0'
,false
o algo parecido, es decir, un valor que se puede evaluar conisset
oempty
, dependiendo de su intención. Si establece regularmente una clave de matriz ennull
y quiere que no signifique nadafalse
, es decir, si en el ejemplo anterior los resultados diferentes deisset
yarray_key_exists
hacen una diferencia en la lógica de su programa, debe preguntarse por qué. La mera existencia de una variable no debería ser importante, solo su valor debería ser de importancia. Si la clave es una banderatrue
/false
, utilicetrue
ofalse
nonull
. La única excepción a esto serían las bibliotecas de terceros que quierannull
significar algo, pero comonull
es tan difícil de detectar en PHP, todavía tengo que encontrar una biblioteca que haga esto.fuente
if ($array["xyz"])
lugar de,isset()
oarray_key_exists()
que considero algo legítimo, ciertamente no son problemas estructurales (corríjame si me equivoco). Agregar mearray_key_exists()
parece un desperdicio terrible.array_key_exists
lugar de un simpleisset($array['key'])
o!empty($array['key'])
. Claro, ambos agregan 7 u 8 caracteres a su código, pero difícilmente lo llamaría un problema. También ayuda a aclarar su código:if (isset($array['key']))
significa que esta variable es opcional y puede estar ausente, mientras queif ($array['key'])
solo significa "si es verdadera". Si recibe un aviso para el último, sabrá que su lógica está mal en alguna parte.Solo escribe una función para eso. Algo como:
que puedes usar como
Haga lo mismo para cosas triviales como
get_number()
,get_boolean()
,get_array()
y así sucesivamente.fuente
<input name="something[]" />
. Esto causaría un error (ya que el recorte no se puede aplicar a las matrices) usando el código anterior, en este caso se debería usaris_string
y posiblementestrval
. Este no es simplemente un caso en el que se deba usarget_array
, ya que la entrada del usuario (maliciosa) tal vez cualquier cosa y el analizador de entrada del usuario nunca debería arrojar un error de todos modos.Creo que una de las mejores formas 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
__get
y__set
métodos ( sobrecarga ).__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 usandoisset()
oempty()
y devolver el valor si existe onull
(o algún otro valor predeterminado) de lo contrario.Después de eso, puede acceder con confianza a los valores de la matriz de esta manera:
$POST->username
y realizar cualquier validación si es necesario sin usar ningunaisset()
s oempty()
s. Siusername
no existe en la matriz global correspondientenull
, se devolverá, por lo que no se generarán advertencias ni avisos.fuente
No me importa usar el
array_key_exists()
función. De hecho, prefiero utilizar esta función específica en lugar de dependerde hackersfunciones que pueden cambiar su comportamiento en el futurocomo(strikedthrough Para evitar susceptibilidades ).empty
yisset
Sin embargo, utilizo una función simple que es útil en esto y en algunas otras situaciones al tratar con índices de matriz :
Digamos que tiene las siguientes matrices:
¿Cómo se obtiene el "valor" de las matrices? Sencillo:
Ya tenemos cubiertas uni y matrices multidimensionales, ¿qué más podemos hacer?
Tome el siguiente fragmento de código, por ejemplo:
Bastante aburrido, ¿no? Aquí hay otro enfoque que usa la
Value()
función:Como ejemplo adicional, tome la
RealIP()
función para una prueba:Limpio, ¿eh? ;)
fuente
isset
yempty
son construcciones del lenguaje , no funciones. En segundo lugar, si alguna de las funciones básicas de la biblioteca o las construcciones del lenguaje cambian su comportamiento, es posible que esté o no arruinado. ¿Y siarray_key_exists
cambia su comportamiento? La respuesta es que no lo hará, siempre que lo esté utilizando como se documenta. Yisset
está documentado para usarse exactamente así. Las funciones del peor de los casos están en desuso con respecto a una versión principal o dos. ¡El síndrome de los NIH es malo!array_key_exists()
comprobar si existe una clave en una matriz ?array_key_exists()
fue creado exactamente para eso , prefiero confiar en él para este propósito queisset()
y especialmenteempty()
cuya descripción oficial es: "determinar si una variable está vacía", no menciona nada si realmente existe. Su comentario y voto negativo es uno de los más ridículos que he presenciado en todo el mes .isset
yempty
hay más o menos fiable quearray_key_exists
y puede hacer exactamente el mismo trabajo. Su segundo ejemplo, de larga duración, puede escribirse como$domain = isset($domain['host']) ? $domain['host'] : 'N/A';
con solo las características del lenguaje principal, sin llamadas de función adicionales o declaraciones necesarias (tenga en cuenta que no necesariamente abogo por el uso del operador ternario; o)). Para las variables escalares ordinarias, aún necesitará usarisset
oempty
, y puede usarlas para matrices exactamente de la misma manera. La "confiabilidad" es una mala razón para no hacerlo.Estoy aqui contigo. Pero los diseñadores de PHP han cometido errores mucho más graves que ese. Aparte de definir una función personalizada para cualquier lectura de valor, no hay forma de evitarlo.
fuente
params["width"] = params["width"] || 5
para establecer valores predeterminados en lugar de todas esas tonterías con lasisset()
llamadas.register_globals
ymagic_quotes
. Los problemas que estos fomentan hacen que las variables no inicializadas parezcan casi inofensivas en comparación.Yo uso estas funciones
Ejemplos
fuente
Bienvenido al operador de fusión nula (PHP> = 7.0.1):
PHP dice:
fuente
Crea una función que regrese
false
si no se establece y, si se especifica,false
si está vacía. Si es válido, devuelve la variable. Puede agregar más opciones como se ve en el siguiente código:fuente
El software no funciona mágicamente por la gracia de Dios. Si está esperando algo que falta, debe 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 compilará o bloqueará simplemente su aplicación si es nula.
Además, hace que su aplicación no se pueda mantener y se volverá loco cuando sucedan cosas inesperadas. El rigor del lenguaje es imprescindible y PHP, por diseño, está mal en muchos aspectos. Te convertirá en un mal programador si no lo sabes.
fuente
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 bastante importante para todo el proceso.
Si su E_NOTICE proviene de $ _GET o $ _POST, entonces deben comprobarse con empty () junto con todas las demás comprobaciones de seguridad que esos datos deberían tener que pasar.
Si proviene de fuentes o bibliotecas externas, debe incluirse 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 asignar una nueva variable al retorno de una función que devuelve FALSE en caso de falla. Estos deben incluirse en una prueba que, en caso de falla, pueda asignar a la variable un valor predeterminado aceptable que el código pueda manejar, o lanzar una excepción que el código pueda manejar.
Estas cosas hacen que el código sea más largo, agregan bloques adicionales y agregan pruebas adicionales, pero no estoy de acuerdo con usted en que creo que definitivamente agregan un valor adicional.
fuente
¿Qué pasa con el uso del
@
operador?Por ejemplo:
Puede decir que esto es malo porque no tiene control de lo que sucede "dentro" de $ foo (si fuera una llamada de función que contiene un error de PHP, por ejemplo), pero si solo usa esta técnica para variables, esto es equivalente a:
fuente
if(isset($foo))
es suficiente en realidad. VolveráTRUE
si la expresión se evalúa comoTRUE
.