Tu codes en PHP depuis des années et tu dois te mettre à Java, pour un nouveau poste, une mission ou une application Android ? Bonne nouvelle : tu sais déjà programmer, il te reste à changer de réflexes. Ce guide présente Java pour développeur PHP à travers les différences clés, en pratique : typage, compilation, classes, collections, exceptions, outils et frameworks, toujours avec le code PHP et son équivalent Java côte à côte.
PHP et Java se ressemblent plus qu’on ne le croit : syntaxe héritée du C, classes, interfaces, exceptions, et même les mots-clés public, private, static ou final. PHP moderne a d’ailleurs emprunté beaucoup à Java (types, interfaces, énumérations). Pourtant, les premières semaines sont souvent déroutantes : le compilateur refuse ton code, les tableaux n’ont rien à voir, et ton application ne « meurt » plus à la fin de chaque requête.
Ce guide est pensé pour un développeur PHP qui découvre Java : on part de ce que tu connais pour arriver à son équivalent, en expliquant le pourquoi des différences. À la fin, tu sauras lire et écrire du Java idiomatique, et tu sauras quoi installer pour démarrer.

Les différences d’exécution (script contre JVM), le typage statique, la compilation, les classes et les records, les collections qui remplacent le tableau PHP, les exceptions vérifiées, les null, les chaînes, les outils (Maven, Gradle, JUnit) et la correspondance entre l’écosystème Laravel/Symfony et Spring Boot.
Différence n°1 : le modèle d’exécution
C’est la différence la plus profonde, et celle dont on parle le moins. En PHP, chaque requête HTTP lance ton script, qui répond puis disparaît avec toutes ses variables. En Java, l’application démarre une seule fois dans la JVM (machine virtuelle Java) et reste en mémoire pour traiter toutes les requêtes, en parallèle.

| 🐘 PHP | ☕ Java | |
|---|---|---|
| Durée de vie | Le temps d’une requête | Tant que le serveur tourne |
| Mémoire entre requêtes | Rien n’est conservé (sauf cache, session) | Les objets restent en mémoire |
| Parallélisme | Plusieurs processus PHP-FPM | Plusieurs threads dans un seul processus |
| Démarrage | Instantané | Quelques secondes (puis très rapide) |
| Erreur fatale | Termine la requête en cours | Peut faire tomber toute l’application si elle n’est pas gérée |
Une variable static ou un attribut de service Spring est partagé entre toutes les requêtes et tous les utilisateurs. Stocker « l’utilisateur courant » dans un attribut, comme on le ferait sans risque dans un script PHP, mélangerait les données de plusieurs visiteurs. En Java web, l’état propre à une requête se passe en paramètre.
Différence n°2 : le typage statique et la compilation
PHP est dynamiquement typé (même si les types déclarés de PHP 7 et 8 ont beaucoup réduit l’écart). Java est statiquement typé : chaque variable a un type connu à la compilation, et le compilateur refuse le code incohérent avant qu’il ne s’exécute.
<?php
$prenom = "Alice";
$age = 31;
$age = "trente et un"; // autorisé : la variable change de type
function saluer(string $nom): string {
return "Salut $nom";
}
echo saluer($prenom);PHP// Java 25 : un fichier source « compact », lancé avec java Saluer.java
String saluer(String nom) {
return "Salut " + nom;
}
void main() {
String prenom = "Alice";
int age = 31;
// age = "trente et un"; // ❌ erreur de compilation : incompatible types
var ville = "Liège"; // inférence de type : ville est un String, pour toujours
IO.println(saluer(prenom) + " de " + ville + ", " + age + " ans");
}Saluer.java (Java 25)Le mot-clé var (Java 10+) évite de répéter le type quand il est évident, mais le typage reste statique : var n’est pas le $ de PHP. Côté workflow, Java ajoute une étape : le code source .java est compilé en bytecode .class, exécuté par la JVM. Les IDE et Maven/Gradle le font pour toi, et depuis Java 11 tu peux même lancer java Main.java directement.
| Type PHP | Type Java | Remarque |
|---|---|---|
int | int / long | int sur 32 bits (±2,1 milliards), long sur 64 bits |
float | double | Pour l’argent : BigDecimal, jamais double |
bool | boolean | Pas de conversion implicite : if (1) ne compile pas |
string | String | Immuable, comparé avec .equals() |
array | List, Map, Set, tableau int[] | Voir la différence n°4 |
?string | String (peut être null) | Ou Optional<String> en retour de méthode |
mixed | Object | À éviter : on perd l’intérêt du typage |
Différence n°3 : tout est classe (ou presque)
En PHP, un fichier peut contenir des fonctions libres et du code exécuté directement. En Java classique, tout vit dans une classe, et un fichier public porte le nom de sa classe (Utilisateur.java contient public class Utilisateur). Les espaces de noms PHP deviennent des packages, qui correspondent aux dossiers.
<?php
namespace App\Modele;
final class Utilisateur
{
public function __construct(
private readonly string $nom,
private readonly string $email,
) {}
public function nom(): string { return $this->nom; }
public function salutation(): string
{
return "Bonjour {$this->nom}";
}
}src/Modele/Utilisateur.phppackage be.lmcode.modele;
public final class Utilisateur {
private final String nom;
private final String email;
public Utilisateur(String nom, String email) {
this.nom = nom;
this.email = email;
}
public String getNom() { return nom; }
public String salutation() {
return "Bonjour " + nom; // pas de $this-> : this est implicite
}
}src/main/java/be/lmcode/modele/Utilisateur.javaPour une simple classe de données, Java propose depuis la version 16 les records, l’équivalent des propriétés promues readonly de PHP 8, avec en prime equals(), hashCode() et toString() générés :
public record Utilisateur(String nom, String email) {
public String salutation() {
return "Bonjour " + nom;
}
}
var alice = new Utilisateur("Alice", "[email protected]");
IO.println(alice.nom()); // accesseur généré : nom(), pas getNom()
IO.println(alice); // Utilisateur[nom=Alice, [email protected]]Record Java| PHP | Java |
|---|---|
namespace App\Modele; | package be.lmcode.modele; |
use App\Modele\Utilisateur; | import be.lmcode.modele.Utilisateur; |
$this->nom | this.nom (ou simplement nom) |
self::CONSTANTE | CONSTANTE ou Classe.CONSTANTE |
Classe::methode() | Classe.methode() |
new Utilisateur(...) | new Utilisateur(...) (identique !) |
instanceof | instanceof, avec pattern matching : if (o instanceof Utilisateur u) |
trait | Pas d’équivalent direct : méthodes default d’interface, ou composition |
Différence n°4 : adieu le tableau à tout faire
En PHP, array sert à tout : liste, dictionnaire, pile, ensemble… En Java, chaque usage a sa structure, avec des performances garanties. C’est probablement le plus gros changement d’habitude.
<?php
$langages = ['PHP', 'Java', 'Python']; // liste
$langages[] = 'Go';
$ages = ['Alice' => 31, 'Bruno' => 27]; // dictionnaire
$ages['Chloé'] = 35;
foreach ($ages as $nom => $age) {
echo "$nom a $age ans\n";
}
$adultes = array_filter($ages, fn($a) => $a >= 30);
$noms = array_map('strtoupper', array_keys($adultes));PHPimport java.util.*;
List<String> langages = new ArrayList<>(List.of("PHP", "Java", "Python"));
langages.add("Go");
Map<String, Integer> ages = new HashMap<>(Map.of("Alice", 31, "Bruno", 27));
ages.put("Chloé", 35);
for (var e : ages.entrySet()) {
IO.println(e.getKey() + " a " + e.getValue() + " ans");
}
List<String> noms = ages.entrySet().stream()
.filter(e -> e.getValue() >= 30)
.map(e -> e.getKey().toUpperCase())
.toList();JavaLes fonctions array_filter, array_map et array_reduce trouvent leur équivalent dans l’API Stream (filter, map, reduce, collect). Et attention : List.of() et Map.of() créent des collections non modifiables, d’où le new ArrayList<>(...). Pour bien choisir entre ArrayList, HashMap, HashSet ou TreeMap, notre guide des collections Java détaille chaque structure avec schémas et complexités.
Différence n°5 : les chaînes et les comparaisons
String a = "bonjour";
String b = new String("bonjour");
IO.println(a == b); // false ! == compare les références (les objets)
IO.println(a.equals(b)); // true : compare le contenu
// Concaténation : + (pas de point comme en PHP)
String message = "Salut " + a + " !";
// Interpolation : String.format ou formatted()
String ligne = "%s a %d ans".formatted("Alice", 31);
// Text blocks (Java 15+) : l'équivalent du heredoc PHP
String html = """
<p>Bonjour %s</p>
""".formatted("Alice");Java : les pièges des chaînes| PHP | Java |
|---|---|
"Salut " . $nom | "Salut " + nom |
"Salut $nom" | "Salut %s".formatted(nom) |
strlen($s) | s.length() |
strtolower($s) | s.toLowerCase() |
str_contains($s, "x") | s.contains("x") |
explode(",", $s) | s.split(",") (expression régulière !) |
implode(", ", $t) | String.join(", ", liste) |
$a === $b | a.equals(b) (ou Objects.equals(a, b) si null possible) |
Comparer deux String avec == fonctionne parfois (grâce au cache des chaînes littérales)… puis échoue en production avec des chaînes venant d’une base de données ou d’un formulaire. Pour les objets, utilise toujours .equals().
Différence n°6 : null et Optional
PHP 8 a l’opérateur ?-> (nullsafe) et ??. Java n’a ni l’un ni l’autre, et appeler une méthode sur null lève la célèbre NullPointerException. Pour signaler qu’une méthode peut ne rien renvoyer, Java utilise Optional :
<?php
$ville = $utilisateur?->adresse?->ville ?? 'Inconnue';PHPOptional<Utilisateur> trouve = depot.findByEmail("[email protected]");
String ville = trouve
.map(Utilisateur::adresse)
.map(Adresse::ville)
.orElse("Inconnue");
// Valeur par défaut simple
String nom = Objects.requireNonNullElse(saisie, "Anonyme");JavaDifférence n°7 : les exceptions vérifiées
La gestion des exceptions ressemble beaucoup à PHP (try, catch, finally, throw), avec une particularité : les exceptions vérifiées (checked exceptions). Si une méthode peut lever une IOException, le compilateur t’oblige à la gérer ou à la déclarer avec throws.
// Le compilateur exige de traiter IOException
static String lireFichier(Path chemin) throws IOException {
return Files.readString(chemin);
}
void main() {
try {
IO.println(lireFichier(Path.of("config.txt")));
} catch (NoSuchFileException e) {
IO.println("Fichier introuvable : " + e.getFile());
} catch (IOException e) {
IO.println("Erreur de lecture : " + e.getMessage());
}
}
// try-with-resources : ferme automatiquement la ressource (comme un fclose garanti)
try (var lecteur = Files.newBufferedReader(Path.of("data.csv"))) {
lecteur.lines().forEach(IO::println);
}JavaLes exceptions qui héritent de RuntimeException (comme IllegalArgumentException) ne sont pas vérifiées : c’est l’équivalent des exceptions PHP habituelles. Spring Boot les utilise massivement.
Différence n°8 : match, enum et switch
Bonne surprise : l’expression match de PHP 8 a son jumeau en Java avec le switch moderne (Java 14+), et les énumérations PHP 8.1 ressemblent beaucoup aux enum Java.
<?php
enum Statut: string {
case AFaire = 'a_faire';
case EnCours = 'en_cours';
case Terminee = 'terminee';
}
$libelle = match ($statut) {
Statut::AFaire => 'À faire',
Statut::EnCours => 'En cours',
Statut::Terminee => 'Terminée',
};PHP 8.1enum Statut { A_FAIRE, EN_COURS, TERMINEE }
String libelle = switch (statut) {
case A_FAIRE -> "À faire";
case EN_COURS -> "En cours";
case TERMINEE -> "Terminée";
}; // le compilateur vérifie qu'aucun cas n'est oubliéJavaDifférence n°9 : les outils et l’écosystème Java pour développeur PHP
Tu ne repars pas de zéro : chaque outil de ton quotidien PHP a son équivalent Java.

Composer → Maven ou Gradle
Le composer.json devient un pom.xml (Maven) ou un build.gradle (Gradle). Ils gèrent les dépendances et la compilation, les tests et le packaging. Les bibliothèques viennent de Maven Central, l’équivalent de Packagist.
<dependencies>
<!-- équivalent de : composer require laravel/framework -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- équivalent de : composer require --dev phpunit/phpunit -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>pom.xml (extrait)Laravel / Symfony → Spring Boot
Spring Boot est le framework web dominant en Java. Si tu connais Symfony, tu seras en terrain familier : injection de dépendances, annotations (attributs en PHP), contrôleurs, services, dépôts. Comparons une petite route d’API :
<?php
use App\Models\Tache;
use Illuminate\Http\Request;
Route::get('/taches/{id}', function (int $id) {
return Tache::findOrFail($id);
});
Route::post('/taches', function (Request $request) {
$data = $request->validate(['titre' => 'required|max:150']);
return response()->json(Tache::create($data), 201);
});Laravel — routes/api.php@RestController
@RequestMapping("/taches")
public class TacheController {
private final TacheRepository depot;
public TacheController(TacheRepository depot) { // injection par le constructeur
this.depot = depot;
}
@GetMapping("/{id}")
public Tache lire(@PathVariable long id) {
return depot.findById(id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Tache creer(@Valid @RequestBody NouvelleTache demande) {
return depot.save(new Tache(demande.titre()));
}
}
record NouvelleTache(@NotBlank @Size(max = 150) String titre) {}Spring Boot — TacheController.javaLa structure est plus verbeuse, mais tout est explicite et vérifié à la compilation : le type de l’identifiant, la forme du corps de la requête, les règles de validation. Pour comparer avec une API équivalente en JavaScript, vois notre tutoriel API REST avec Node.js, Express et MySQL.
| Besoin | Écosystème PHP | Écosystème Java |
|---|---|---|
| Framework web | Laravel, Symfony | Spring Boot, Quarkus, Micronaut |
| ORM | Eloquent, Doctrine | JPA / Hibernate, Spring Data |
| Migrations | Laravel Migrations, Doctrine Migrations | Flyway, Liquibase |
| Tests unitaires | PHPUnit, Pest | JUnit 5, AssertJ, Mockito |
| Analyse statique | PHPStan, Psalm | Le compilateur + SpotBugs, SonarLint |
| Formatage | PHP-CS-Fixer | Spotless, google-java-format |
| Gabarits HTML | Blade, Twig | Thymeleaf |
| Interface desktop | — | JavaFX (voir notre logiciel de restaurant JavaFX) |
Installer Java et écrire son premier programme (Java pour développeur PHP)
- Installe un JDK 25 (la version LTS actuelle), par exemple la distribution gratuite Eclipse Temurin d’Adoptium.
- Vérifie l’installation dans un terminal :
java -version. - Choisis un éditeur : IntelliJ IDEA (la référence en Java, édition Community gratuite) ou VS Code avec le pack d’extensions Java.
- Crée un fichier
Bonjour.javaet lance-le directement, sans étape de compilation manuelle.
// Lancer avec : java Bonjour.java
void main() {
var langages = java.util.List.of("PHP", "Java");
for (var langage : langages) {
IO.println("Bonjour depuis " + langage + " !");
}
}Bonjour.javaDepuis Java 25, plus besoin du fameux public static void main(String[] args) ni d’une classe pour un petit programme : la méthode void main() et la classe IO rendent les premiers pas aussi simples qu’un script PHP. Pour un vrai projet, génère un squelette avec Spring Initializr (Spring Boot) ou mvn archetype:generate.
Si tu restes sur VS Code, installe l’« Extension Pack for Java » de Microsoft en plus de tes indispensables : notre sélection des meilleures extensions VS Code t’aidera à garder un éditeur rapide.
Feuille de route Java pour développeur PHP : 4 semaines
| Semaine | Objectif | Exercice conseillé |
|---|---|---|
| 1 | Syntaxe, types, classes, records, compilation | Réécrire un petit script PHP (calculatrice, convertisseur) en Java |
| 2 | Collections, Streams, exceptions, Optional | Lire un fichier CSV et produire des statistiques |
| 3 | Maven/Gradle, tests JUnit, organisation en packages | Écrire les tests de la semaine 2 |
| 4 | Spring Boot : contrôleurs, services, JPA | Recréer une petite API CRUD que tu as déjà faite en Laravel ou en PHP natif |
Java pour développeur PHP : les 8 réflexes à oublier
- Mettre un
$devant les variables (le compilateur te le rappellera vite). - Concaténer avec un point : en Java, c’est
+. - Comparer des chaînes avec
==: utilise.equals(). - Utiliser un tableau associatif pour tout : choisis
List,MapouSet. - Compter sur la conversion automatique :
"5" + 1donne"51", etif ("")ne compile pas. - Stocker l’état d’une requête dans un attribut
staticou de service : il est partagé entre tous les utilisateurs. - Utiliser
doublepour de l’argent : préfèreBigDecimal. - Ignorer les avertissements de l’IDE : en Java, ils signalent souvent un vrai bug.
FAQ : Java pour développeur PHP
Java est-il difficile à apprendre quand on connaît PHP ?
Non. La syntaxe est très proche (héritée du C) et les concepts orientés objet sont les mêmes. Les vraies nouveautés sont le typage statique, la compilation, les collections et le modèle d’exécution permanent de la JVM. Compte quelques semaines pour être à l’aise.
Quel est l’équivalent de Laravel en Java ?
Spring Boot est le framework le plus utilisé, plus proche de Symfony dans sa philosophie. Quarkus et Micronaut sont des alternatives modernes, plus légères au démarrage.
Quelle version de Java apprendre en 2026 ?
La dernière version LTS, Java 25, sortie en septembre 2025. Elle simplifie beaucoup les débuts avec void main() et la classe IO, tout en restant la version supportée à long terme par les entreprises.
Faut-il apprendre Java ou Kotlin après PHP ?
Pour le développement Android, Kotlin est le langage recommandé par Google. Pour le back-end en entreprise, Java reste majoritaire. Apprendre Java d’abord facilite ensuite le passage à Kotlin, qui tourne sur la même JVM.
Peut-on faire du web avec Java comme avec PHP ?
Oui, mais différemment : on ne dépose pas des fichiers sur un serveur Apache. L’application Spring Boot embarque son propre serveur web et se lance comme un programme, souvent derrière Nginx ou dans un conteneur Docker.
Conclusion
Passer de PHP à Java, ce n’est pas réapprendre à programmer : c’est changer de réflexes. Retiens l’essentiel de ce guide Java pour développeur PHP : l’application vit en permanence dans la JVM, le compilateur vérifie les types avant l’exécution, chaque usage du tableau PHP a sa collection dédiée, les chaînes se comparent avec equals(), et l’écosystème (Maven, JUnit, Spring Boot) a un équivalent pour chacun de tes outils.
Le meilleur moyen de progresser reste de réécrire en Java un projet que tu as déjà réalisé en PHP, par exemple notre application de planning PHP/MySQL. Tu verras vite que la rigueur de Java devient un confort. Pour approfondir, les tutoriels officiels dev.java sont gratuits et à jour.

