Dans ce tutoriel complet, vous allez apprendre comment structurer votre code en PHP et en JavaScript autour d’un point d’entrée « main », comment en Python, et comment procéder si vous avez besoin qu’un programme “reste à l’écoute” (boucle d’écoute).
Nous allons vous expliquer, pas à pas, ce qu’est une fonction main
, à quoi elle sert, les avantages et les limites de cette façon de coder, et comment l’implémenter concrètement en PHP (site classique, CLI, et solutions temps réel) et en JavaScript (navigateur et Node.js).
Ce tutoriel est conçu pour être accessible, même si vous débutez. Les parties sont claires et indépendantes, vous pouvez les lire dans l’ordre ou aller directement à la section qui vous intéresse.
Concepts généraux de la fonction « main » en python
La notion de « fonction main()
» est simplement un moyen de donner un point d’entrée clair à votre programme. Dans certains langages (C, Python), c’est un idiome courant : on définit main()
puis on l’appelle si le script est exécuté directement. Cela facilite la lecture, les tests unitaires et l’importation du code depuis d’autres fichiers.
La « boucle d’écoute » est un mécanisme qui permet à un programme de rester actif et d’attendre des événements (requêtes HTTP, messages WebSocket, nouveaux fichiers, tâches à exécuter). Dans un contexte serveur ou outil CLI de fond (daemon), il est fréquent d’utiliser une boucle ou une boucle événementielle (event loop) pour gérer ces événements.
Il y a deux concepts à connaître :
- L’exécution en mode requête-réponse (typique de PHP côté web) : le script démarre pour répondre à une requête, puis s’arrête.
- L’exécution en mode processus long (typique de Node.js ou d’un script CLI) : le processus reste actif et gère des événements pendant longtemps.
Comprendre la différence vous aidera à choisir la bonne approche.
En PHP : la fonction main et le mode d’écoute
Pourquoi PHP n’a pas de main()
natif ?
PHP, historiquement, est conçu pour être exécuté sur chaque requête HTTP. Le moteur PHP lit le fichier, exécute les instructions du haut vers le bas, puis termine l’exécution. Il n’y a donc pas d’obligation d’avoir une fonction main()
.
Cependant, il est possible, surtout pour structurer un projet particulier, de définir une fonction main()
que vous appellerez explicitement. Cela rend le code plus lisible et facilite les tests et les inclusions.
Exemple simple : définir et appeler main()
Créez un fichier hello.php
:
<?php
function main(): void {
echo "Hello from main() in PHP\n";
}
main();
Dans ce petit script, la fonction main
contient le code principal. L’appel de la fonction main()
déclenche l’exécution quand le fichier est lancé.
Ce code fonctionnera en CLI ou sur un serveur web (si vous l’avez dans un script appelé par le navigateur).
Condition pour exécuter main()
uniquement si le fichier est exécuté directement
Si vous voulez que main()
ne s’exécute que lorsque le fichier est lancé directement et non pas lorsqu’il est inclus par un autre fichier, utilisez une comparaison robuste :
<?php
function main(): void {
echo "Exécuté directement\n";
}
if (realpath(__FILE__) === realpath($_SERVER['SCRIPT_FILENAME'])) {
main();
}
Ici, __FILE__
désigne le chemin du fichier courant. $_SERVER['SCRIPT_FILENAME']
désigne le script principal lancé et realpath()
normalise les chemins. La comparaison vérifie que ce fichier est bien le script principal.
Cela est l’équivalent de if __name__ == "__main__":
en Python.
Boucle d’écoute en PHP : en CLI
En CLI (ligne de commande), vous pouvez créer une boucle infinie pour « écouter » :
<?php
function main(): void {
while (true) {
echo "[".date('H:i:s')."] J'écoute...\n";
sleep(1); // évite de saturer le CPU
}
}
main();
Étapes pour exécuter :
- Sauvegardez dans
daemon.php
. - Lancez en CLI :
php daemon.php
. - Pour le détacher du terminal :
nohup php daemon.php >daemon.log 2>&1 &
ou utilisezscreen
/tmux
.
Important,
sleep(1)
pause une seconde entre chaque itération, ce qui empêche la boucle de consommer toute la CPU.
Ce pattern est utile pour un worker qui doit surveiller une file, un dossier, ou effectuer des tâches périodiques.
Un démon (ou daemon) est un programme informatique qui s’exécute en arrière-plan sans interaction directe avec un utilisateur. Il démarre généralement au lancement du système d’exploitation et continue de fonctionner pour accomplir des tâches spécifiques, comme la gestion des requêtes d’impression, la surveillance des processus, ou l’envoi de courriels. Pensez-y comme à un « esprit » du système qui travaille discrètement et constamment pour s’assurer que certaines fonctions essentielles fonctionnent correctement et de manière autonome.
Boucle événementielle en PHP : ReactPHP
Le PHP moderne peut aussi utiliser une boucle événementielle via ReactPHP pour un comportement proche de Node.js. Pour commencer :
Étapes d’installation :
- Créez un dossier projet et placez-vous dedans.
- Initialisez Composer (gestionnaire PHP) :
composer init
puiscomposer require react/event-loop
. - Créez un fichier
loop.php
:
<?php
require __DIR__ . '/vendor/autoload.php';
$loop = React\EventLoop\Factory::create();
$loop->addPeriodicTimer(1.0, function () {
echo '[' . date('H:i:s') . "] Tick depuis ReactPHP\n";
});
$loop->run();
React\EventLoop\Factory::create()
crée une boucle événementielle.addPeriodicTimer
exécute la fonction toutes les secondes.run()
démarre la boucle et garde le processus vivant.
L’utilisation typique de ce principe est un serveur WebSocket en PHP (via Ratchet) ou pour des tâches asynchrones, traitement de flux de données, etc.
WebSocket en PHP : Ratchet (aperçu)
Pour des communications temps réel, Ratchet est une librairie utilisée pour créer des serveurs WebSocket en PHP. Le flux général se traduis de la manière suivante :
composer require cboden/ratchet
- Écrire un composant qui implémente
MessageComponentInterface
. - Lancer le serveur Ratchet et gérer
onOpen
,onMessage
,onClose
,onError
.
Je fournis ici un aperçu simple (sans entrer dans tous les détails d’installation) car l’API de Ratchet demande quelques étapes d’autoloading et de configuration.
Un WebSocket est une technologie qui permet de créer une connexion bidirectionnelle et persistante entre un client (comme un navigateur web) et un serveur. Contrairement aux requêtes web traditionnelles qui s’ouvrent, se ferment et se relancent à chaque échange d’informations, le WebSocket maintient le lien ouvert en continu. Cela permet au serveur et au client de s’envoyer des données en temps réel et instantanément, sans avoir besoin de demander constamment s’il y a de nouvelles informations. On l’utilise pour des applications nécessitant une mise à jour en direct comme les chats en ligne, les jeux multijoueurs ou les notifications instantanées.
Avantages et limites en PHP
Avantages :
- Facilité pour écrire un
main()
simple et lisible. - En CLI, possibilité d’écrire des workers et daemons en PHP.
- ReactPHP et Ratchet permettent du temps réel en PHP sans redémarrer à chaque requête.
Limites :
- PHP n’a pas été historiquement conçu pour des processus très longs; attention aux fuites de mémoire.
- Les mises à jour de PHP sont plus simples à appliquer sur des processus courts ; sur des daemons, il faudra redémarrer proprement.
- Pour du temps réel massif, d’autres environnements (Node.js, Go) peuvent être plus adaptés.
Cas pratique en PHP : un petit watcher de dossier
Voici un exemple complet et simple : un script CLI qui surveille un dossier inbox/
et déplace les fichiers vers processed/
lorsqu’ils apparaissent.
Commencez par créer la structure :
mkdir projet-watcher && cd projet-watcher
mkdir inbox processed
Créez le fichier watcher.php
:
<?php
$inbox = __DIR__ . '/inbox';
$processed = __DIR__ . '/processed';
function processFile(string $path, string $destDir): void {
$filename = basename($path);
$dest = $destDir . '/' . $filename;
if (rename($path, $dest)) {
echo "[" . date('H:i:s') . "] Traité : $filename\n";
} else {
echo "[" . date('H:i:s') . "] Erreur en traitant : $filename\n";
}
}
while (true) {
$files = array_diff(scandir($inbox), ['..', '.']);
foreach ($files as $file) {
$full = $inbox . '/' . $file;
if (is_file($full)) {
processFile($full, $processed);
}
}
sleep(2);
}
Pour exécuter ce fichier :

Des formations informatique pour tous !
Débutant ou curieux ? Apprenez le développement web, le référencement, le webmarketing, la bureautique, à maîtriser vos appareils Apple et bien plus encore…
Formateur indépendant, professionnel du web depuis 2006, je vous accompagne pas à pas et en cours particulier, que vous soyez débutant ou que vous souhaitiez progresser. En visio, à votre rythme, et toujours avec pédagogie.
Découvrez mes formations Qui suis-je ?php watcher.php
Pour le mettre en arrière-plan :
nohup php watcher.php > watcher.log 2>&1 &
Explication pas à pas :
scandir($inbox)
liste les fichiers.- On ignore
.
et..
. rename()
déplace le fichier, ce qui simule le traitement.sleep(2)
évite une boucle serrée.
Ce petit script montre comment PHP en CLI peut « écouter » un état (présence de fichiers) et agir en conséquence.
JavaScript : la fonction main, la boucle et un event loop
Fonction main()
en JavaScript ?
JavaScript n’impose pas non plus une fonction main()
, mais vous pouvez la définir pour structurer votre code. En pratique, on retrouve trois contextes principaux : navigateur (frontend), Node.js (backend), et scripts CLI.
Exemple simple :
function main() {
console.log("Hello from main() in JS");
}
main();
Exécution conditionnelle en Node.js
Pour exécuter main()
uniquement si le fichier est lancé directement (et non importé avec require
), en Node.js on utilise require.main === module
:
async function main() {
console.log("Exécuté directement en Node.js");
}
if (require.main === module) {
main();
}
Explication :
require.main
référence le module principal chargé par Node.- Si votre fichier est le point d’entrée, la condition est vraie.
Boucle d’écoute en Node.js : serveur HTTP
Node.js fonctionne naturellement avec une boucle événementielle et garde le processus actif dès qu’il y a un serveur qui écoute. Exemple d’un serveur HTTP minimal :
const http = require('http');
function main() {
const server = http.createServer((req, res) => {
res.end('Hello from Node.js server');
});
server.listen(3000, () => {
console.log('Serveur en écoute sur http://localhost:3000');
});
}
if (require.main === module) main();
Ici, createServer
définit la gestion des requêtes et server.listen
démarre l’écoute : Node.js garde le processus en vie grâce à son event loop.
Boucle d’écoute en Node.js : WebSocket
Pour du temps réel, on peut utiliser le module ws
. Pour commencer, on Initialise le projet :
mkdir ws-server && cd ws-server
npm init -y
npm install ws
Ensuite, on va créer server.js
:
const WebSocket = require('ws');
function main() {
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
ws.send('Bienvenue sur le serveur WebSocket');
ws.on('message', (message) => {
console.log('Message reçu:', message);
ws.send(`Echo: ${message}`);
});
});
console.log('WebSocket en écoute sur ws://localhost:8080');
}
if (require.main === module) main();
Enfin, on exécute : node server.js
- Le serveur WebSocket garde Node.js actif sans que vous gériez explicitement une boucle.
- Les événements
connection
etmessage
sont appelés par l’event loop.
Boucle en CLI Node.js
Si vous voulez un worker Node.js qui tourne en boucle, utilisez un while(true)
asynchrone ou setInterval
, mais attention à ne pas bloquer l’event loop :
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function main() {
while (true) {
console.log('Worker actif');
await sleep(1000);
}
}
if (require.main === module) main();
I
mportant :await sleep(1000)
cède la main à l’event loop et évite un blocage CPU.- Ce pattern est sûr pour un worker Node.js.
Frontend (navigateur) : écouter sans bloquer
Côté navigateur, vous ne devez jamais bloquer le thread principal. On utilise des événements et des timers non bloquants :
Exemple index.html
:
<!doctype html>
<html>
<body>
<button id="btn">Cliquez</button>
<script>
document.getElementById('btn').addEventListener('click', () => {
console.log('Bouton cliqué');
});
setInterval(() => {
console.log('Intervalle toutes les secondes');
}, 1000);
</script>
</body>
</html>
Ici, addEventListener
gère les événements utilisateur tandis que setInterval
exécute périodiquement du code sans bloquer la page.
Cas pratique avec Node.js : Un chat WebSocket simple
Voici un cas pratique complet : un serveur WebSocket qui relaie les messages à tous les clients.
Pour commencer, Initialisez :
npm init -y
npm install ws.
Puis créez le fichier chat-server.js
:
const WebSocket = require('ws');
function main() {
const wss = new WebSocket.Server({ port: 8080 });
const clients = new Set();
wss.on('connection', (ws) => {
clients.add(ws);
ws.send('Vous êtes connecté au chat');
ws.on('message', (msg) => {
for (const client of clients) {
if (client.readyState === WebSocket.OPEN) {
client.send(msg);
}
}
});
ws.on('close', () => clients.delete(ws));
});
console.log('Chat WebSocket en écoute sur ws://localhost:8080');
}
if (require.main === module) main();
Lancez :
node chat-server.js
Côté client navigateur, connectez-vous ainsi :
const ws = new WebSocket('ws://localhost:8080');
ws.onmessage = e => console.log('Reçu:', e.data);
ws.onopen = () => ws.send('Bonjour depuis le navigateur');
Explication :
- Chaque message reçu est envoyé à tous les clients.
- Node.js gère cela sans boucle explicite : l’event loop s’en occupe.
Avantages et limites en JavaScript
Les avantages :
- Node.js est conçu pour des processus longs grâce à son event loop.
- Excellente gestion du temps réel et des connexions simultanées.
- Côté navigateur, l’approche événementielle est naturelle pour l’interaction utilisateur.
Les limites :
- Une boucle synchrone bloquante dans le navigateur gèlera la page.
- En Node.js, attention aux opérations CPU-intensives qui bloquent l’event loop ; il faut déléguer au worker threads ou à des services externes.
- Les patterns asynchrones peuvent être source de confusions si l’on mélange trop de callbacks.
Comparaison : quand utiliser PHP et / ou JS ?
Quand privilégier PHP (avec main
ou worker)
Utilisez PHP pour un worker en CLI si :
- Vous avez déjà une base de code en PHP et vous voulez réutiliser des bibliothèques.
- Vous devez exécuter des tâches planifiées ou surveiller un état simple (fichiers, queues).
- Vous préférez écrire rapidement des scripts sans changer d’écosystème.
Privilégiez ReactPHP ou Ratchet si vous avez besoin de communication asynchrone en PHP. Cependant, pour de la forte charge temps réel, Node.js ou des langages adaptés aux serveurs long running peuvent être plus efficaces.
Quand privilégier JavaScript / Node.js
Préférez Node.js si :
- Vous construisez un service temps réel ou un serveur WebSocket à forte concurrence.
- Vous avez des besoins en streaming, microservices, ou API performantes en I/O.
- Vous souhaitez utiliser le même langage côté client et côté serveur.
Bonnes pratiques communes
- Évitez les fuites de mémoire : libérez les ressources, surveillez la consommation, et redémarrez proprement les processus longs.
- Externalisez la logique lourde en tâches ou services (workers), ne bloquez pas l’event loop.
- Utilisez un gestionnaire de processus :
pm2
pour Node.js,systemd
ousupervisord
pour PHP/CLI. - Testez en local avant de déployer en production et prévoyez des scripts de redémarrage automatiques lors des mises à jour.
Vous savez maintenant ce que représente une fonction main()
en PHP et en JavaScript, et comment imiter le comportement de if __name__ == "__main__":
en PHP et avec Node.js, et comment créer des boucles d’écoute en CLI ou via une boucle événementielle.
En PHP, vous pouvez structurer votre code avec main()
et utiliser ReactPHP ou Ratchet pour des processus longs ou du temps réel.
En JavaScript, Node.js offre une event loop native, idéale pour des serveurs qui restent à l’écoute et pour le temps réel, tandis que le navigateur s’appuie sur des événements et des timers non bloquants.