J'ai plusieurs applications plus anciennes qui lancent beaucoup de messages "xyz is undefined" et "undefined offset" lors de l'exécution sur le niveau d'erreur E_NOTICE, car l'existence de variables n'est pas explicitement vérifiée à l'aide de isset()
et consorts.
J'envisage de travailler avec eux pour les rendre compatibles E_NOTICE, car les avis sur les variables ou les décalages manquants peuvent sauver des vies, il peut y avoir des améliorations mineures des performances à gagner, et c'est globalement la manière la plus propre.
Cependant, je n'aime pas ce qu'inflige des centaines de isset()
empty()
et array_key_exists()
s à mon code. Il se gonfle, devient moins lisible, sans rien gagner en valeur ou en sens.
Comment structurer mon code sans excès de contrôles de variables, tout en étant compatible E_NOTICE?
la source
Réponses:
Pour ceux qui sont intéressés, j'ai développé ce sujet dans un petit article, qui fournit les informations ci-dessous sous une forme un peu mieux structurée: The Definitive Guide To PHP's isset And empty
IMHO, vous devriez penser non seulement à rendre l'application "E_NOTICE compatible", mais à restructurer le tout. Avoir des centaines de points dans votre code qui essaient régulièrement d'utiliser des variables inexistantes ressemble à un programme plutôt mal structuré. Essayer d'accéder à des variables inexistantes ne devrait jamais arriver, d'autres langages hésitent à cela au moment de la compilation. Le fait que PHP vous permette de le faire ne signifie pas que vous devriez le faire.
Ces avertissements sont là pour vous aider , pas pour vous ennuyer. Si vous recevez un avertissement "Vous essayez de travailler avec quelque chose qui n'existe pas!" , votre réaction devrait être "Oups, mon mauvais, laissez-moi résoudre ce problème dès que possible." Sinon, comment allez-vous faire la différence entre "des variables qui fonctionnent très bien et non définies" et un code honnêtement erroné qui peut conduire à de graves erreurs ? C'est aussi la raison pour laquelle vous développez toujours, toujours avec le rapport d'erreur passé à 11 et continuez à brancher votre code jusqu'à ce que pas un seul
NOTICE
est émis. La désactivation des rapports d'erreurs est réservée aux environnements de production, afin d'éviter les fuites d'informations et de fournir une meilleure expérience utilisateur, même en cas de code bogué.Élaborer:
Vous aurez toujours besoin
isset
ouempty
quelque part dans votre code, le seul moyen de réduire leur occurrence est d'initialiser correctement vos variables. Selon la situation, il existe différentes manières de procéder:Arguments de fonction:
Il n'est pas nécessaire de vérifier si
$bar
ou$baz
sont définis à l'intérieur de la fonction car vous venez de les définir, tout ce dont vous avez besoin est de savoir si leur valeur est évaluée àtrue
oufalse
(ou quoi que ce soit d'autre).Variables régulières n'importe où:
Initialisez vos variables en haut d'un bloc de code dans lequel vous allez les utiliser. Cela résout le
!isset
problème, garantit que vos variables ont toujours une valeur par défaut connue, donne au lecteur une idée de ce sur quoi le code suivant fonctionnera et sert ainsi également de sorte d'auto-documentation.Tableaux:
La même chose que ci-dessus, vous initialisez le tableau avec les valeurs par défaut et les écrasez par les valeurs réelles.
Dans les cas restants, disons un modèle où vous produisez des valeurs qui peuvent ou non être définies par un contrôleur, il vous suffira de vérifier:
Si vous vous retrouvez à utiliser régulièrement
array_key_exists
, vous devriez évaluer à quoi vous l'utilisez. Le seul moment où cela fait une différence, c'est ici:Comme indiqué ci-dessus cependant, si vous initialisez correctement vos variables, vous n'avez pas besoin de vérifier si la clé existe ou non, car vous le savez. Si vous obtenez le tableau à partir d' une source externe, la valeur sera très probablement pas
null
mais''
,0
,'0'
,false
ou quelque chose comme ça, soit une valeur que vous pouvez évaluer avecisset
ouempty
, selon votre intention. Si vous définissez régulièrement une clé de tableau surnull
et que vous voulez qu'elle ait une signification autre quefalse
, c'est-à-dire si, dans l'exemple ci-dessus, les résultats différents deisset
etarray_key_exists
font une différence dans la logique de votre programme, vous devriez vous demander pourquoi. La simple existence d'une variable ne devrait pas être importante, seule sa valeur devrait être importante. Si la clé est un indicateurtrue
/false
, utiliseztrue
oufalse
nonnull
. La seule exception à cela serait les bibliothèques tierces qui veulentnull
signifier quelque chose, mais commenull
c'est si difficile à détecter en PHP, je n'ai pas encore trouvé de bibliothèque qui le fasse.la source
if ($array["xyz"])
plutôt queisset()
ouarray_key_exists()
que je trouve quelque peu légitimes, certainement pas des problèmes structurels (corrigez-moi si je me trompe). L'ajoutarray_key_exists()
me semble un terrible gaspillage.array_key_exists
au lieu d'un simpleisset($array['key'])
ou!empty($array['key'])
. Bien sûr, les deux ajoutent 7 ou 8 caractères à votre code, mais je n'appellerais pas cela un problème. Cela aide également à clarifier votre code:if (isset($array['key']))
signifie que cette variable est en effet facultative et peut être absente, alorsif ($array['key'])
que signifie simplement "si vrai". Si vous recevez un avis pour ce dernier, vous savez que votre logique est foirée quelque part.Écrivez simplement une fonction pour cela. Quelque chose comme:
que vous pouvez utiliser comme
Faites la même chose pour des choses triviales comme
get_number()
,get_boolean()
,get_array()
et ainsi de suite.la source
<input name="something[]" />
. Cela provoquerait une erreur (car le trim ne peut pas être appliqué aux tableaux) en utilisant le code ci-dessus, dans ce cas, il faut utiliseris_string
et éventuellementstrval
. Ce n'est pas simplement un cas où l'on devrait utiliser l'unget_array
ou l'autre puisque l'entrée utilisateur (malveillante) peut-être n'importe quoi et l'analyseur d'entrée utilisateur ne devrait jamais générer d'erreur de toute façon.Je pense que l'un des meilleurs moyens de résoudre ce problème est d'accéder aux valeurs des tableaux GET et POST (COOKIE, SESSION, etc.) via une classe.
Créez une classe pour chacun de ces tableaux et déclarez les méthodes
__get
et__set
( surcharge ).__get
accepte un argument qui sera le nom d'une valeur. Cette méthode doit vérifier cette valeur dans le tableau global correspondant, en utilisantisset()
ouempty()
et renvoyer la valeur si elle existe ounull
(ou une autre valeur par défaut) sinon.Après cela, vous pouvez accéder en toute confiance aux valeurs du tableau de cette manière:
$POST->username
et faire toute validation si nécessaire sans utiliser deisset()
s ou deempty()
s. Siusername
n'existe pas dans le tableau global correspondant, alorsnull
sera retourné, donc aucun avertissement ou avis ne sera généré.la source
Cela ne me dérange pas d'utiliser la
array_key_exists()
fonction. En fait, je préfère utiliser cette fonction spécifique plutôt que de me fier à des fonctions depiratagequi peuvent changer leur comportement à l'avenircomme(barré pour éviter les susceptibilités ).empty
etisset
Cependant, j'utilise une fonction simple qui est utile dans ce cas, et dans d'autres situations pour traiter les index de tableau :
Disons que vous avez les tableaux suivants:
Comment obtenez-vous la «valeur» des tableaux? Facile:
Nous avons déjà couvert des tableaux unidimensionnels et multidimensionnels, que pouvons-nous faire d'autre?
Prenez le morceau de code suivant par exemple:
Assez ennuyeux n'est-ce pas? Voici une autre approche utilisant la
Value()
fonction:Comme exemple supplémentaire, prenez la
RealIP()
fonction pour un test:Neat, hein? ;)
la source
isset
etempty
sont des constructions de langage , pas de fonctions. Deuxièmement, si des fonctions / constructions de langage de base de la bibliothèque changent de comportement, vous risquez ou non d'être vissé. Et siarray_key_exists
change son comportement? La réponse est que non, tant que vous l'utilisez tel que documenté. Etisset
est documenté pour être utilisé exactement ainsi. Les pires fonctions des cas sont obsolètes sur une version majeure ou deux. Le syndrome du NIH est mauvais!array_key_exists()
pour vérifier si une clé existe dans un tableau ?!array_key_exists()
a été créé exactement pour cela , je m'appuie plutôt dessus pour cela queisset()
et spécialementempty()
dont la description officielle est: "déterminer si une variable est vide", ne mentionne rien si elle existe réellement. Votre commentaire et votre vote négatif sont l'un des plus ridicules dont j'ai été témoin de tout le mois .isset
etempty
ne sont ni plus ni moins fiables quearray_key_exists
et peuvent faire exactement le même travail. Votre deuxième exemple long peut être écrit comme$domain = isset($domain['host']) ? $domain['host'] : 'N/A';
avec juste des fonctionnalités de langage de base, aucun appel de fonction ou déclaration supplémentaire n'est nécessaire (notez que je ne préconise pas nécessairement l'utilisation de l'opérateur ternaire; o)). Pour les variables scalaires ordinaires, vous devrez toujours utiliserisset
ouempty
, et vous pouvez les utiliser pour les tableaux exactement de la même manière. La «fiabilité» est une mauvaise raison pour ne pas le faire.Je suis là avec toi. Mais les concepteurs PHP ont fait des erreurs bien plus pires que cela. À moins de définir une fonction personnalisée pour toute lecture de valeur, il n'y a aucun moyen de contourner cela.
la source
params["width"] = params["width"] || 5
pour définir les valeurs par défaut au lieu de toutes ces absurdités avec lesisset()
appels.register_globals
etmagic_quotes
. Les problèmes qu'ils suscitent font que les variables non initialisées semblent presque inoffensives en comparaison.J'utilise ces fonctions
Exemples
la source
Bienvenue dans l'opérateur de fusion nul (PHP> = 7.0.1):
PHP dit:
la source
Créez une fonction qui retourne
false
si elle n'est pas définie et, si elle est spécifiée,false
si elle est vide. S'il est valide, il renvoie la variable. Vous pouvez ajouter plus d'options comme indiqué dans le code ci-dessous:la source
Le logiciel ne fonctionne pas comme par magie par la grâce de Dieu. Si vous attendez quelque chose qui manque, vous devez le gérer correctement.
Si vous l'ignorez, vous créez probablement des failles de sécurité dans vos applications. Dans les langages statiques, accéder à une variable non définie n'est tout simplement pas possible. Il ne compilera ni ne plantera simplement votre application si elle est nulle.
De plus, cela rend votre application impossible à gérer et vous allez devenir fou lorsque des choses inattendues se produisent. La rigueur du langage est un must et PHP, de par sa conception, est faux à bien des égards. Cela fera de vous un mauvais programmeur si vous n'êtes pas au courant.
la source
Je ne sais pas quelle est votre définition de la lisibilité, mais l'utilisation correcte des blocs empty (), isset () et try / throw / catch est assez importante pour l'ensemble du processus.
Si votre E_NOTICE provient de $ _GET ou $ _POST, alors ils doivent être vérifiés par rapport à empty () avec tous les autres contrôles de sécurité que ces données doivent passer.
S'il provient de sources externes ou de bibliothèques, il doit être encapsulé dans try / catch.
S'il vient de la base de données, $ db_num_rows () ou son équivalent doit être vérifié.
Si cela provient de variables internes, elles doivent être correctement initialisées. Souvent, ces types d'avis proviennent de l'affectation d'une nouvelle variable au retour d'une fonction qui renvoie FALSE en cas d'échec. Ceux-ci devraient être enveloppés dans un test qui, en cas d'échec, peut soit affecter à la variable une valeur par défaut acceptable que le code peut gérer, soit lever une exception que le code peut gérer.
Ces choses allongent le code, ajoutent des blocs supplémentaires et ajoutent des tests supplémentaires, mais je ne suis pas d'accord avec vous en ce sens que je pense qu'ils ajoutent certainement une valeur supplémentaire.
la source
Qu'en est-il de l'utilisation de l'
@
opérateur?Par exemple:
Vous pouvez dire que c'est mauvais parce que vous n'avez aucun contrôle sur ce qui se passe "à l'intérieur" de $ foo (si c'est un appel de fonction qui contient une erreur PHP par exemple), mais si vous n'utilisez cette technique que pour les variables, c'est équivalent à:
la source
if(isset($foo))
est assez en fait. Il retourneraTRUE
si l'expression est évaluée àTRUE
.