Analyse détaillée de la différence entre Property_exists et ISSET , et quels sont leurs avantages et inconvénients respectifs?
Property_exists () et isset () sont souvent utilisés pour "juger si les propriétés des objets existent". Mais la sémantique des deux n'est pas la même: la première se concentre sur "si l'attribut est déclaré / existant dans un objet ou une classe", tandis que le second se concentre sur "si la variable ou l'attribut est définie et non nul ". Comprendre cette différence peut éviter les pièges causés par des pointeurs vides, des attributs non initialisés et des méthodes magiques.
Une conclusion de phrase
- Property_exists (\ $ obj, 'x') : quelle que soit la valeur (y compris les attributs de type NULL , non initialisés, les attributs privés / protégés invisibles), renvoie vrai tant que "cette propriété existe sur l'objet".
- isset (\ $ obj-> x) : renvoyez true uniquement lorsque " x est défini et non nul "; Les attributs de type NULL , UNSED et non initialisés sont tous return faux . __isset () est déclenché pour les propriétés surchargées.
Table de comparaison de base
| Scène | propriété_exists | Isset |
|---|---|---|
| La déclaration d'attribut existe et la valeur est non nul | vrai | vrai |
| La déclaration d'attribut existe et la valeur est nul | vrai | FAUX |
| L'attribut n'est pas déclaré / n'existe pas | FAUX | Faux (et peut déclencher __isset ) |
| Propriétés privées / protégées | vrai | Cela dépend s'il est visible / implémenté __isset (généralement faux) |
| Attribut de type (non initialisé) | vrai | FAUX (l'accès direct lancera des erreurs, ISSet est faux) |
| Propriétés dynamiques (8.2+ Création dépréciée par défaut) | L'existence est vraie | Vrai quand il existe et n'est pas nul |
| S'il faut déclencher la méthode magique | Ne pas déclencher __get / __ iSset | Peut déclencher __isset |
| Peut être utilisé sur les chaînes de nom de classe | Oui (vérifiez les propriétés déclarées de la classe) | Non (l'accès à la variable / objet est requis) |
| Performance (à peu près) | Appel de fonction, légèrement plus lent | Structure linguistique, très rapide |
Exemple minimum: voir la différence en un coup d'œil
<?php
class User {
public ?string $nickname = null; // Déclaré,Mais null
private int $age = 18; // Attributs privés
}
\$u = new User();
var_dump(property_exists(\$u, 'nickname')); // true:propriété“exister”
var_dump(isset(\$u->nickname)); // false:La valeur est null
var_dump(property_exists(\$u, 'age')); // true:Même si c'est private Absolument“exister”
var_dump(isset(\$u->age)); // false:Pas visible,Et non implémenté __isset
var_dump(property_exists(\$u, 'email')); // false:Non énoncé/不exister
var_dump(isset(\$u->email)); // false:Pas sur l'objet
Interaction avec les propriétés dactylographiées
Depuis PHP 7.4, les attributs de type peuvent être "déclarés mais non initialisés". En ce moment:
- Property_exists : true (parce que la déclaration existe).
- isset (\ $ obj-> prop) : false ; Si vous lisez directement \ $ obj-> propose directement , une erreur sera augmentée: la propriété tapée ... ne doit pas être accessible avant l'initialisation .
<?php
class Post {
public string $title; // Non initialisé
}
\$p = new Post();
var_dump(property_exists(\$p, 'title')); // true
var_dump(isset(\$p->title)); // false
// echo \$p->title; // Erreur fatale:Non initialisé的类型propriété
Coopération avec les méthodes magiques
Lorsque la classe implémente la surcharge d'attribut ( __get / __ set / __ iSset ):
- Property_exists ne déclenche pas __get ou __isset , il ne se penche que la "table d'attribut réelle".
- isset (\ $ obj-> x) essaiera d'appeler __isset ('x') pour vous permettre de personnaliser "s'il est considéré comme défini".
<?php
class Box {
private array \$data = ['a' => null, 'b' => 1];
public function __isset(string \$name): bool {
// Personnaliser:只要键exister就算“Ensemble”(哪怕La valeur est null)
return array_key_exists(\$name, \$this->data);
}
}
\$box = new Box();
var_dump(isset(\$box->a)); // true(parce que __isset retour true)
Propriétés dynamiques et PHP 8.2+
En partant de PHP 8.2, la création dynamique des attributs pour les classes normales ( \ $ obj-> foo = 1 et il n'y a pas de FOO sur la classe) éliminera les avertissements par défaut. Pratiques recommandées:
- déclarer explicitement les attributs; ou
- Utilisez # [allowdynamicproperties] sur la classe; ou
- Utilisez des conteneurs de stockage d'attribut StdClass / Explicit.
Une fois que l'objet a cette propriété:
- Property_exists (\ $ obj, 'foo') est vrai ;
- isset (\ $ obj-> foo) dépend de la question de savoir si sa valeur est nul .
Chacun a ses propres avantages et inconvénients
propriété_exists
- Avantages : la sémantique est claire (si elle existe / déclarée), peut vérifier les attributs privés / protégés, peut vérifier les chaînes de nom de classe et ne déclenchera pas de méthodes magiques.
- Inconvénients : Il est impossible de juger si "initialisé / non nulle", les appels de fonction sont des frais généraux et des rendements plus "conservateurs" aux attributs surchargés.
Isset
- Avantages : extrêmement rapide, peut collaborer avec __isset pour exprimer la sémantique commerciale et un jugement intuitif de "aucun null n'est disponible".
- Inconvénients : NULL est toujours considéré comme "Unset", qui est facile de confondre "valeur nul" avec "manquant"; Il ne peut pas être utilisé pour les chaînes de nom de classe; Il est facile de marcher sur les attributs de type non initialisés (l'accès direct provoquera des erreurs).
Des mauvais usages et des pièges communs
- Traitez "EXIST" comme "disponible" : Retour True à Property_Exists ne signifie pas que la valeur est lisible ou a été initialisée.
- Traitez Null comme "manquant" : l'ISSet ne peut pas voir NULL , et il doit être coordonné avec Array_key_exists et les opérateurs de fusion ternary / vide.
- Ignorez la Visibilité / Méthode magique : ISSET peut retourner faux car il n'est pas visible ou peut être réécrit par __isset .
- Propriétés dynamiques dans 8.2+ : La création intentionnelle de propriétés dynamiques générera un avertissement de dépréciation, et il est recommandé de le déclarer explicitement.
Modèles pratiques et meilleures pratiques
1) Confirmez que "la déclaration existe", mais ne vous soucie pas de la valeur
<?php
if (property_exists(\$user, 'id')) {
// Vous pouvez en outre déterminer s'il a été initialisé/Non null
}
2) Confirmer "Disponible et non nulle"
<?php
if (isset(\$user->id)) {
// Usage sûr \$user->id
}
3) Il est nécessaire de faire la distinction entre "null" et "manquant" (cartographie des tableaux / données)
<?php
// Scène de la table:Veuillez utiliser array_key_exists
\$data = ['a' => null];
var_dump(isset(\$data['a'])); // false
var_dump(array_key_exists('a', \$data)); // true:键exister,La valeur est null
4) Il est nécessaire de juger à la fois l'existence et la disponibilité
<?php
if (property_exists(\$dto, 'amount') && isset(\$dto->amount)) {
// Se rencontrer en même temps“声明exister”et“Non null Disponible”
}
5) Méthode d'écriture stable pour l'interface / DTO (y compris les attributs de type)
<?php
class OrderDTO {
public ?int \$amount = null; // Sémantique nul explicite
}
\$o = new OrderDTO();
// Qualification et défaut
\$value = \$o->amount ?? 0; // Fusion vide:null Ou donner une valeur par défaut lorsqu'elle n'est pas définie
Quand choisir qui?
- Faire la "vérification structurelle" ou la "vérification réfléchissante" (si la classe déclare une certaine propriété ou est-elle compatible avec l'interface): utilisez Property_exists .
- Rendre le "jugement de disponibilité des entreprises" (la propriété est définie et n'est disponible que si elle n'est pas nul ): utilisez d'abord ISSet .
- Rencontre des attributs de type : éviter de lire directement non initialisé; ISSET revient faux et est une sentinelle de sécurité.
- Besoin de coopérer avec la surcharge : règles de "disponibilité" personnalisées en implémentant __isset .
Conclusion
La séparation de "l'existence" de la "disponibilité" est la clé pour choisir Property_exists ou ISSET . Le premier répond "Cet attribut est-il là?" Et ce dernier répond "peut-il être utilisé maintenant." Sélectionnez des outils par sémantique et votre code sera plus stable et plus facile à entretenir.