isset vs empty: différence entre isset et empty

Les fonctions isset() et empty() sont parmi les plus utilisées en PHP, mais elles provoquent souvent de la confusion. Chaque fonction a un rôle très précis, et comprendre leurs différences permet d’écrire un code robuste, prévisible et sans pièges subtils.

Exemple pratique avec isset dans le cas d’une checkbox HTML

<?php
/**
 * Cas concret : une checkbox HTML n'apparaît dans $_POST 
 * UNIQUEMENT si elle est cochée par l'utilisateur
 */
if (isset($_POST['newsletter'])) {
    echo "✅ L'utilisateur s'est abonné à la newsletter.";
    echo "Valeur reçue : " . $_POST['newsletter']; // "on"
    subscribeUser($_POST['email'], true);
} else {
    echo "❌ Pas d'abonnement demandé.";
    subscribeUser($_POST['email'], false);
}
?>
<form method="POST">
    <input type="email" name="email" placeholder="Votre email">
    <input type="checkbox" name="newsletter" value="on">
    <button type="submit">S'inscrire</button>
</form>

Pourquoi isset() ici ? Une checkbox non cochée n’existe pas du tout dans la variable super globale $_POST. Elle ne transmet jamais $_POST['newsletter'] = '' ou null. Donc isset() est parfait pour détecter sa présence.

Exemple pratique avec empty avec un champ de recherche

<?php
/**
 * Cas concret : un champ de recherche texte
 * L'utilisateur peut laisser vide → afficher tous les produits
 */
$query = $_GET['q'] ?? '';

if (empty($query)) {
    echo "🔍 Aucun mot-clé → Affichage de tous les produits.";
    $produits = getAllProducts();
} else {
    echo "🔍 Recherche pour : " . htmlspecialchars($query);
    $produits = searchProducts(trim($query));
}

foreach ($produits as $produit) {
    echo "<div>" . $produit['name'] . "</div>";
}
?>
<form method="GET">
    <input type="text" name="q" value="<?= htmlspecialchars($query) ?>">
    <button type="submit">Rechercher</button>
</form>

Pourquoi empty() ici ? L’utilisateur peut soumettre une chaîne vide '' en laissant le champ vide. empty('') renvoie true, ce qui correspond parfaitement au besoin métier.

Analyse détaillée des comportements

Ce que teste vraiment isset()

<?php
echo "=== TEST isset() ===\n";

$var1 = '';           // Chaîne vide
$var2 = 0;            // Zéro entier  
$var3 = null;         // Null explicite
$var4 = false;        // Booléen faux
$var5 = [];           // Tableau vide
$var6 = 'test';       // Chaîne valide

var_dump(isset($var1)); // true  ✓ Existe, même vide
var_dump(isset($var2)); // true  ✓ 0 existe
var_dump(isset($var3)); // false ✗ null = "n'existe pas" pour isset()
var_dump(isset($var4)); // true  ✓ false existe
var_dump(isset($var5)); // true  ✓ Tableau vide existe
var_dump(isset($var6)); // true  ✓ Parfait
?>

Règle isset() : « Cette variable existe-t-elle dans le monde PHP et n’est-elle pas null ? »

Ce que teste vraiment empty()

<?php
echo "=== TEST empty() ===\n";

$var1 = '';           // Chaîne vide
$var2 = 0;            // Zéro entier
$var3 = null;         // Null explicite  
$var4 = false;        // Booléen faux
$var5 = [];           // Tableau vide
$var6 = 'test';       // Chaîne valide

var_dump(empty($var1)); // true  ✓ "Vide" selon PHP
var_dump(empty($var2)); // true  ✓ 0 = "vide"
var_dump(empty($var3)); // true  ✓ null = vide
var_dump(empty($var4)); // true  ✓ false = vide
var_dump(empty($var5)); // true  ✓ [] = vide
var_dump(empty($var6)); // false ✗ Contient du contenu
?>

Règle empty() : « Cette valeur est-elle useless selon les règles arbitraires de PHP ? » (''0falsenull[]'0'0.0)

Tableau comparatif complet

Valeur testéeisset()empty()Explication
Non définiefalsetrueN’existe pas du tout
nullfalsetrueExiste mais « nulle »
'' (chaîne vide)truetrueExiste mais vide
0 (entier)truetrueExiste, valeur nulle
'0' (chaîne)truetrueExiste, représente zéro
falsetruetrueExiste, booléen faux
[] (tableau vide)truetrueExiste mais vide
'test'truefalseExiste + utile
[1,2,3]truefalseExiste + utile

Guide décisionnel : quand utiliser quoi ?

🎯 Utiliser isset() dans ces 4 cas :

Checkbox HTML

if (isset($_POST['cgv'])) { /* Accepté */ }

Paramètres optionnels (true/false/0 tous OK)

if (isset($config['debug'])) { /* Debug activé ou pas */ }

Compteurs/Quantités (0 = légitime)

if (isset($cart['total'])) { echo $cart['total']; } // 0€ OK

Toggle volontaire

if (isset($settings['public'])) { /* Public ou privé choisi */ }

🎯 Utiliser empty() dans ces 4 cas :

Champs texte (vide = '')

if (empty($_POST['nom'])) { /* Nom obligatoire */ }

Recherches/Filtres

if (empty($_GET['q'])) { showAll(); }

Résultats de base de données

if (empty($users)) { echo "Aucun utilisateur"; }

Cache vide

if (empty($cache['page'])) { generatePage(); }

🎯 Les deux ensemble pour validation stricte :

// Champs OBLIGATOIRES = existe + non vide
if (isset($_POST['age']) && !empty($_POST['age']) && ctype_digit($_POST['age'])) {
    $age = (int)$_POST['age'];
    if ($age >= 18) { /* Accès autorisé */ }
}

Erreurs classiques à éviter

❌ Erreur 1 : Utiliser empty() pour les compteurs

if (!empty($cart['quantity'])) { /* ❌ 0 ignoré ! */ }
// CORRECT :
if (isset($cart['quantity'])) { /* 0€ accepté */ }

❌ Erreur 2 : isset() pour les chaînes vides

if (isset($_POST['recherche'])) { search(); } // ❌ '' déclenche recherche
// CORRECT :
if (!empty($_POST['recherche'])) { search(); }

Récapitulatif mnémotechnique

isset()  → "EXISTE-T-ELLE ?" (physique)
empty()  → "EST-ELLE USELESS ?" (métier)

Checkbox ? → isset()
Texte ?    → empty()
0 OK ?     → isset()
Obligatoire ? → isset() + !empty()

Cette distinction claire permet d’écrire du code PHP prévisible et sans surprise !

isset() vs empty() : quelle différence de performance en PHP ?

<?php
// Benchmark simple (à tester avec microtime() sur 1M itérations)
$var1 = '';    // Chaîne vide
$var2 = null;  // Null
$var3 = 0;     // Zéro

// isset() : 1 test rapide
$start = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
    isset($var1);
}
echo "isset() : " . (microtime(true) - $start) . "s\n";

// empty() : isset() + règles supplémentaires
$start = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
    empty($var1);
}
echo "empty() : " . (microtime(true) - $start) . "s\n";

Résultat typique : isset() est 10-20% plus rapide car empty() fait un test supplémentaire.

Comparaison dans des cas réels

<?php

$_POST['nom'] = '';  // Soumis mais vide

// Version 1 : isset() seul (plus rapide)
if (isset($_POST['nom'])) {
    $nom = $_POST['nom'];  // 1 seul test
}

// Version 2 : empty() seul (légèrement plus lent)
if (!empty($_POST['nom'])) {
    $nom = $_POST['nom'];  // isset() + test "vide"
}

// Version 3 : Les deux (le plus sûr, mais 2 tests)
if (isset($_POST['nom']) && !empty($_POST['nom'])) {
    $nom = $_POST['nom'];
}

Tableau de performance pratique entre isset et empty en PHP

Scénarioisset()empty()Recommandation
1M itérations0.12s0.15sisset() +20% plus rapide
Validation formulaire (10 champs)0.0001ms0.00012msDifférence négligeable
Boucle sur gros tableauGagnantPerdantPrivilégier isset()
Cas simple (1 variable)ÉgalitéÉgalitéChoisir selon besoin fonctionnel

Recommandations performance + lisibilité

<?php
// ✅ BON : Si tu veux juste "existe et non null"
if (isset($data['key'])) { }

// ✅ BON : Si tu veux "non vide" (0, '', false exclus)
if (!empty($data['key'])) { }

// ✅ OPTIMALE pour formulaires : fonction helper
function isValidInput($input) {
    return isset($input) && $input !== '';  // isset() + test simple
}

if (isValidInput($_POST['nom'])) {
    // Traitement...
}

Verdict : La différence est négligeable dans 99% des cas réels. Privilégier isset() dans les boucles intensives, mais choisir d’abord selon la sémantique métier (existence vs contenu). La lisibilité > micro-optimisations.

Pourquoi limiter isset() et empty() en PHP moderne ?

En PHP moderne (7.0+), certains développeurs recommandent de limiter voire éviter les fonctions isset() et empty() au profit d’approches plus explicites et typées. Ces fonctions, bien qu’utiles historiquement, présentent des limitations qui peuvent compliquer la maintenance du code à long terme.

Comportements ambigus et surprises

Les fonctions isset() et empty() ont des comportements qui peuvent surprendre les développeurs expérimentés.

$var = null;
isset($var);   // false ❌ Surprise ! La variable existe pourtant
empty($var);   // true

$var = '';     // Chaîne vide  
isset($var);   // true
empty($var);   // true ❌ 0, '', false sont tous considérés "vides"

$array = ['key' => null];
isset($array['key']);  // false ❌ La clé existe bel et bien !

Problème principal : isset() teste deux choses à la fois (existence + non-nullité), tandis que empty() applique une liste arbitraire de 7 cas considérés comme « vides ». Ces règles magiques créent des pièges subtils difficiles à mémoriser.

Code verbeux et répétitif

// Classique et prolixe
if (isset($data['user']['name']) && !empty($data['user']['name'])) {
    $name = $data['user']['name'];
}

Ce pattern se répète partout, rendant le code difficile à lire et à maintenir.

Masque les vrais problèmes

isset() et empty() cachent les erreurs de variables non déclarées au lieu de les corriger à la source avec error_reporting(E_NOTICE).

Pourquoi PHP moderne change la donne ?

PHP 7+ et 8+ introduisent des outils plus puissants et explicites.

Opérateur de coalescence null ?? (PHP 7.0+)

Cet opérateur remplace parfaitement le pattern isset() ? $var : 'default'.

// Avant (verbeux)
$name = isset($user['name']) ? $user['name'] : 'Invité';

// Après (plus clair et concis)
$name = $user['name'] ?? 'Invité';

Déclarations strictes et typage (PHP 7+)

Le typage statique élimine le besoin de ces vérifications dynamiques.

// Avec typage nullable
function processUser(?string $name): void {
    if ($name === null) {
        $name = 'Invité';
    }
    // Plus besoin d'isset() ou empty() !
}

// Ou avec valeur par défaut
function processUser(string $name = 'Invité'): void {
    // Toujours une chaîne valide
}

Chaînes de coalescence null (PHP 7.4+)

// Priorité multiple en une ligne
$page = $_GET['page'] ?? $_POST['page'] ?? $_SESSION['page'] ?? 1;

Alternatives modernes recommandées

Pour vérifier l’existence : Typage nullable + ??

// ❌ À éviter
if (isset($_POST['id'])) {
    $id = $_POST['id'];
}

// ✅ Moderne et explicite
$id = $_POST['id'] ?? null;
if ($id !== null) {
    // Traitement sécurisé
}

Pour vérifier le « non-vide » : Tests explicites par type

// ❌ Magique et ambigu
if (!empty($input)) { }

// ✅ Clair et prévisible
if (is_string($input) && $input !== '') { }
if (is_numeric($input) && $input > 0) { }
if (is_array($input) && count($input) > 0) { }

Helpers explicites (best practice)

function isPresent(mixed $value): bool {
    return $value !== null && $value !== '';
}

function hasValue(array $array, string $key): bool {
    return array_key_exists($key, $array) && 
           $array[$key] !== null && 
           $array[$key] !== '';
}

DTOs / Objets typés (PHP 8+)

class User {
    public function __construct(
        public readonly ?string $name = null
    ) {}
}

$user = new User($_POST['name'] ?? null);
$name = $user->name ?? 'Invité';

Quand conserver isset() et empty() quand même ?

Ces fonctions restent pertinentes dans certains contextes :

  1. Code legacy (PHP 5.x)
  2. Templates simples (éviter la logique complexe)
  3. Superglobales où le typage est impossible
// Toujours légitime pour $_GET/$_POST
if (isset($_GET['id']) && ctype_digit($_GET['id'])) {
    $id = (int)$_GET['id'];
}

Verdict final

AspectPHP AncienPHP Moderne
Syntaxeisset() + empty() partout??, typage strict, tests explicites
LisibilitéMagie, règles arbitrairesClarté, prévisibilité
ErreursMasque les noticesLes expose et corrige
MaintenabilitéPièges subtilsCode auto-documenté

Conclusion : isset() et empty() ne sont pas « mauvais », mais PHP moderne (7.0+) offre des alternatives supérieures. Utilisez-les ponctuellement pour du code legacy ou des superglobales, mais privilégiez les approches typées pour tout nouveau développement. Votre code n’en sera que plus robuste et maintenable à long terme.

Cours

Variables et types

Manipulation de chaînes

Tableaux

Fichiers et système

Sécurité, session et cookie