Menu

Questions d'entretien PHP et leurs réponses (PHP 8)

24 questions d'entretien PHP avec des réponses courtes et exactes pour PHP 8, de == ou === et isset ou empty aux références dans foreach, self ou static, les générateurs, l'injection SQL et le hachage des mots de passe. La plupart des réponses ont du code que vous pouvez exécuter et modifier.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

Voici les questions PHP qui reviennent le plus en entretien, avec des réponses courtes et exactes pour PHP 8.3, et du code là où le code fait passer le message. Prédisez la sortie de chaque bloc avant de cliquer sur Run : c'est ce que teste un recruteur.

Questions d'entretien PHP pour débutants

Qu'est-ce que PHP et comment s'exécute-t-il ?

PHP est un langage de script côté serveur. Un serveur web (Nginx ou Apache) transmet la requête à PHP (en général PHP-FPM), PHP exécute le script depuis le début, et ce qu'il affiche devient la réponse, en général du HTML. Chaque requête repart de zéro : les variables ne survivent pas d'une requête à l'autre, sauf si vous les stockez dans une session, une base de données ou un cache. PHP exécute aussi des scripts en ligne de commande (php script.php).

Quelle est la différence entre == et === ?

== compare après conversion de type, === compare la valeur et le type sans conversion. L'échauffement ci-dessus montre == à l'œuvre : les chaînes numériques sont comparées comme des nombres, donc '10' == '1e1' vaut true. Depuis PHP 8, un nombre comparé à une chaîne non numérique est comparé comme une chaîne, donc 0 == 'a' vaut false (en PHP 7, c'était true). Touchez les cases pour comparer les deux opérateurs :

Comparaison souple (==) et stricte (===)
Point at or tap a cell to read it as PHP.
$a == $btruefalse01"0""1"""null[]"a""10""1e1"
true
false
0
1
"0"
"1"
""
null
[]
"a"
"10"
"1e1"
Every cell computed by PHP 8.3.19.

Utilisez === par défaut. in_array() et array_search() utilisent == sauf si vous passez true en troisième argument.

Quelle est la différence entre echo et print ?

Les deux affichent des chaînes. echo prend plusieurs arguments (echo $a, $b;) et ne renvoie rien ; print en prend un et renvoie 1, il peut donc être utilisé dans une expression. Aucun des deux n'est une fonction, les parenthèses sont donc facultatives. En pratique, tout le monde utilise echo.

Guillemets simples ou doubles ?

Les chaînes entre guillemets doubles interpolent les variables et les séquences d'échappement : "Hi $name\n". Les chaînes entre guillemets simples sont littérales, sauf pour \' et \\ : 'Hi $name\n' affiche exactement ces caractères. La différence de vitesse est négligeable, le choix est donc une question de lisibilité : guillemets doubles quand vous interpolez, guillemets simples sinon.

Quels sont les types de données en PHP ?

Quatre types scalaires (int, float, string, bool), deux types composés (array et object), et deux types spéciaux (null et resource). callable, iterable, mixed et void n'existent que comme déclarations de type, jamais comme type d'une valeur. gettype() et get_debug_type() donnent le type d'une valeur à l'exécution, et var_dump() l'affiche avec la valeur.

Quelle est la différence entre isset, empty et is_null ?

isset($x) vaut true quand la variable existe et ne vaut pas null. empty($x) vaut true quand la variable n'existe pas ou est évaluée à faux (0, '0', '', [], false, null). is_null($x) vaut true pour null, mais affiche un warning sur une variable non définie. isset et empty n'affichent jamais de warning, c'est pourquoi on les utilise sur les clés de tableau.

isset, empty et is_null pour chaque valeur de $x
Point at or tap a cell to read it as PHP.
$xissetemptyis_null
null
false
0
"0"
""
" "
[]
"a"
0.0
Every cell computed by PHP 8.3.19.

La ligne sur laquelle on se trompe est "0" : la chaîne zéro est vide, alors que " " (un espace) ne l'est pas. La page isset donne le tableau complet.

Quelle est la différence entre include et require ?

Les deux insèrent et exécutent un autre fichier. Si le fichier manque, include émet un warning et le script continue, alors que require lève une Error (« Failed opening required »), qui arrête le script sauf si quelque chose l'intercepte. Les variantes _once (include_once, require_once) sautent un fichier déjà chargé, ce qui évite les erreurs « cannot redeclare function ». Utilisez require (ou require_once) pour les fichiers sans lesquels le script ne peut pas s'exécuter, c'est-à-dire presque tous ; l'autoloader de Composer rend inutiles la plupart des inclusions manuelles.

Quelle est la différence entre GET et POST ?

GET envoie les données dans la query string de l'URL ($_GET), elles sont donc visibles, peuvent être mises en favori et ont une longueur limitée ; utilisez-le pour lire, comme la recherche et la pagination. POST envoie les données dans le corps de la requête ($_POST) ; utilisez-le pour tout ce qui modifie un état, comme la connexion, l'enregistrement ou les paiements. Une requête GET ne doit jamais modifier de données, car les liens sont préchargés et explorés par des robots.

Qu'est-ce que l'opérateur de fusion null ?

$a ?? $b renvoie $a s'il existe et ne vaut pas null, sinon $b, sans warning pour une variable ou une clé non définie : $page = $_GET['page'] ?? 1;. ??= n'affecte que si le côté gauche vaut null ou manque. Il diffère de ?:, qui se rabat sur toute valeur évaluée à faux, donc 0 ?: 5 vaut 5 mais 0 ?? 5 vaut 0.

Questions d'entretien PHP de niveau intermédiaire

Que se passe-t-il quand on boucle par référence dans foreach ?

foreach ($arr as &$v) permet de modifier les éléments sur place, mais $v reste une référence vers le dernier élément après la boucle. Réutiliser ce nom dans une seconde boucle écrase alors cet élément :

Le dernier élément vaut 20, pas 30 : pendant la seconde boucle, $v (toujours $arr[2]) reçoit 10, puis 20, puis lui-même. Retirez le // devant unset($v) et relancez. La page foreach détaille les références.

Quelle est la différence entre une classe abstraite et une interface ? Et qu'est-ce qu'un trait ?

Une interface est un contrat : des signatures de méthodes (et des constantes) sans implémentation, et une classe peut en implémenter plusieurs. Une classe abstraite peut contenir des propriétés, des constructeurs et des méthodes terminées, plus des méthodes abstraites que ses enfants doivent écrire ; une classe n'en étend qu'une. Un trait est un ensemble de méthodes copiées dans une classe avec use, pour réutiliser du code entre des classes qui n'ont pas de parent commun.

Une réponse courte qui plaît aux recruteurs : une interface pour dire ce que quelque chose sait faire, une classe abstraite pour partager comment c'est fait, et un trait quand des classes sans lien ont besoin des mêmes quelques méthodes.

Quelle est la différence entre self et static ?

self désigne la classe où le code est écrit. static désigne la classe réellement appelée à l'exécution, ce qu'on appelle la liaison statique tardive. Cela compte dans les méthodes parentes qui créent ou décrivent « ce type d'objet » :

User::createStatic() construit un User. User::createSelf() construit un Model, ce qui viole le type de retour static, donc PHP lève une TypeError. C'est pourquoi les méthodes de fabrique utilisent new static().

Que sont les méthodes magiques ?

Des méthodes que PHP appelle pour vous, qui commencent toutes par deux tirets bas. Les plus courantes : __construct() à la création d'un objet, __destruct() à sa destruction, __toString() quand il est utilisé comme une chaîne, __get() et __set() pour les propriétés inaccessibles, __call() et __callStatic() pour les méthodes manquantes, __invoke() quand l'objet est appelé comme une fonction, et __clone() après clone.

Quelle est la différence entre array_merge() et l'opérateur + ?

array_merge() ajoute à la suite : les clés numériques sont renumérotées et les clés de type chaîne suivantes écrasent les précédentes. + est une union : il garde le tableau de gauche et n'ajoute que les clés manquantes, donc pour une clé en double, la première valeur l'emporte.

+ est le bon outil pour les valeurs par défaut : $options + ['timeout' => 30] garde ce que l'appelant a passé et complète le reste.

Que fait declare(strict_types=1) ?

Sans lui, PHP convertit les arguments scalaires vers le type de paramètre déclaré quand il le peut : passer "5" à un paramètre int donne 5. Avec declare(strict_types=1); comme première instruction d'un fichier, les appels faits depuis ce fichier doivent passer le type exact, sinon une TypeError est levée (un int passé à un paramètre float est le seul élargissement autorisé).

Supprimez la ligne declare et relancez : le second appel renvoie 10 au lieu de lever une erreur.

Un cookie est stocké dans le navigateur et envoyé avec chaque requête, donc le visiteur peut le lire et le modifier. Une session stocke ses données sur le serveur et ne garde qu'un identifiant aléatoire dans un cookie (PHPSESSID). Placez tout ce qui doit être fiable, comme l'identifiant de l'utilisateur connecté, dans $_SESSION ; après la connexion, appelez session_regenerate_id(true). La page sessions et cookies contient le code.

Comment éviter l'injection SQL ?

Ne construisez jamais de SQL en concaténant des saisies. Utilisez des requêtes préparées, pour que les valeurs soient envoyées séparément de la requête :

<?php
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ?');
$stmt->execute([$email]);
$user = $stmt->fetch();

Les marqueurs ne fonctionnent que pour les valeurs. Les noms de tables, les noms de colonnes et ASC/DESC doivent être vérifiés par rapport à une liste autorisée avant d'entrer dans le SQL. Voir PDO.

Comment éviter le XSS ?

Échappez la sortie, pas l'entrée : entourez chaque valeur affichée dans du HTML de htmlspecialchars($value, ENT_QUOTES, 'UTF-8'), ou utilisez un moteur de templates qui le fait automatiquement (Twig, Blade). Dans un <script>, utilisez json_encode() avec JSON_HEX_TAG. Ajoutez un en-tête Content-Security-Policy comme seconde protection.

Comment stocker les mots de passe ?

Avec password_hash($password, PASSWORD_DEFAULT), et vérifiez-les avec password_verify($password, $hash). Ils utilisent bcrypt (ou Argon2id) avec un sel aléatoire stocké dans le hash et un coût volontaire. md5() et sha1() sont inadaptés aux mots de passe car ils sont rapides et sans sel. Utilisez password_needs_rehash() à la connexion pour mettre à jour les anciens hashs.

Questions d'entretien PHP avancées

Que sont les générateurs et quand en utiliser un ?

Une fonction qui contient yield renvoie un Generator qui produit des valeurs une par une, seulement quand on les demande. Cela permet de parcourir une séquence très longue ou infinie sans construire de tableau en mémoire :

Usages typiques : lire un gros fichier ligne par ligne, diffuser des lignes de base de données, et des chaînes de traitement paresseuses. Les générateurs gèrent aussi les clés (yield $key => $value), la délégation (yield from) et la réception de valeurs avec send().

Que sont les closures, et que fait use ?

Une fonction anonyme (function () { ... }) est un objet Closure. Elle ne voit pas les variables extérieures sauf si vous les listez dans use, qui copie la valeur au moment où la closure est créée ; use (&$x) capture plutôt par référence. Les fonctions fléchées (fn ($x) => $x * $factor) capturent automatiquement les variables extérieures, par valeur, et contiennent une seule expression.

Quelle est la différence entre abstract, final et readonly ?

abstract marque une classe qui ne peut pas être instanciée, ou une méthode qu'un enfant doit implémenter. final interdit de redéfinir une méthode ou d'étendre une classe. readonly (PHP 8.1) rend une propriété modifiable une seule fois, depuis l'intérieur de la classe, en général dans le constructeur ; PHP 8.2 a ajouté les classes readonly, où toutes les propriétés sont readonly.

Qu'est-ce que Composer, et qu'est-ce que PSR-4 ?

Composer est le gestionnaire de dépendances de PHP : composer.json liste les paquets, composer.lock fixe les versions exactes, et vendor/autoload.php charge tout. PSR-4 est le standard d'autoloading qui associe un préfixe de namespace à un dossier, si bien que App\Mail\Mailer se trouve dans src/Mail/Mailer.php et est chargé à la première utilisation. Expliquez install (depuis le fichier lock) et update (nouvelles versions, nouveau fichier lock).

Qu'est-ce qui a changé en PHP 8 ?

Les nouveautés phares : en 8.0, arguments nommés, match, l'opérateur nullsafe ?->, types union, promotion des propriétés du constructeur, attributs, str_contains() et une comparaison chaîne/nombre plus raisonnable ; en 8.1, enums, propriétés readonly, syntaxe de callable de première classe (strlen(...)) et fibers ; en 8.2, classes readonly et types autonomes null/true/false ; en 8.3, constantes de classe typées, l'attribut #[\Override] et json_validate() ; en 8.4, property hooks, visibilité asymétrique (public private(set)), array_find() et new Foo()->method() sans parenthèses autour. Beaucoup de fonctions lèvent aussi désormais une TypeError ou une ValueError au lieu de renvoyer false avec un warning.

Comment PHP gère-t-il la mémoire ?

Chaque valeur a un compteur de références ; quand il tombe à zéro, la mémoire est libérée immédiatement. Les objets qui se référencent mutuellement en cycle n'atteignent jamais zéro, donc un collecteur de cycles s'exécute chaque fois que son tampon de racines de cycles possibles se remplit (10 000 entrées par défaut) et les libère (gc_collect_cycles() le lance à la demande). Les tableaux et les chaînes sont en copie à l'écriture : affecter $b = $a partage les données jusqu'à ce que l'un des deux soit modifié. Comme chaque requête commence et se termine proprement, les fuites de mémoire comptent surtout dans les workers de longue durée et les consommateurs de files d'attente.

Comment les tableaux PHP sont-ils implémentés ?

Un tableau PHP est une table de hachage ordonnée : il garde l'ordre d'insertion et associe des clés int ou string à des valeurs, c'est pourquoi le même type sert de liste, de dictionnaire et de pile. Les recherches par clé (isset($arr[$key])) prennent un temps constant en moyenne, alors que in_array() parcourt chaque valeur. Les clés de type chaîne qui ressemblent à des entiers sont converties : $a['1'] et $a[1] sont le même élément.

Exercices de code fréquents en entretien

De petits exercices souvent demandés en direct. Chaque fonction est une réponse courante ; exécutez-les, ajoutez vos propres entrées (y compris une entrée vide), et soyez prêt à expliquer la complexité en temps, ce que le recruteur vérifie en général.

Questions fréquentes

Comment se préparer à un entretien de développeur PHP ?

Assurez-vous de pouvoir expliquer et coder les bases sans les chercher : comparaison et types, tableaux et leurs fonctions, POO (interfaces, classes abstraites, traits, static), exceptions et sécurité (requêtes préparées, htmlspecialchars, password_hash). Connaissez ensuite un framework (Laravel ou Symfony) et Composer assez bien pour présenter un projet que vous avez construit.

Quelle version de PHP faut-il connaître pour un entretien ?

PHP 8. Les recruteurs attendent que vous connaissiez les nouveautés de 8.0 à 8.3 : arguments nommés, match, l'opérateur nullsafe ?->, types union, promotion des propriétés du constructeur, enums, propriétés readonly et syntaxe de callable de première classe. Ne mentionnez le comportement de PHP 7 que là où il a changé, comme 0 == "a".

Quelles questions PHP pose-t-on aux débutants ?

Surtout les bases du langage : == ou ===, echo ou print, guillemets simples ou doubles, isset ou empty, include ou require, GET ou POST, sessions ou cookies, et des tâches simples sur les tableaux comme inverser, filtrer ou compter des valeurs. Attendez-vous à au moins un petit exercice de code.

Quelles questions PHP pose-t-on aux développeurs expérimentés ?

La conception et le fonctionnement interne : interfaces ou classes abstraites, traits, liaison statique tardive, références, générateurs et mémoire, exceptions et gestion des erreurs, injection SQL et transactions, cache, autoloading de Composer, et la façon dont vous structureriez ou testeriez une fonctionnalité. On attend des réponses qui pèsent le pour et le contre, pas des définitions.

Illustration des langages de programmation de Coddy

Apprendre à coder avec Coddy

COMMENCER