Pour la première étape, un appel à la fonction lcfirst() sur la chaîne de caractères considérée résout le problème très efficacement.

Le passage en casse haute de toutes les lettres précédées d'un espace, qui correspond à l'étape 3, est déjà moins évident.

PHP dispose de la fonction inverse de lcfirst(), à savoir ucfirst().

Il reste donc à localiser les lettres sur lesquelles il faut l'appliquer.

Pour cela, preg_replace() est notre amie, puisque cette fonction est capable d'exécuter une fonction sur chaque remplacement, via le drapeau e.

Il suffit donc de lui demander de remplacer tous les espaces par la lettre qui le suit en casse haute, de la manière suivante :

<?php $string = preg_replace('/\s+(.)/ue', 'ucfirst(\'\\1\')', $string); ?>

Ma chaîne étant au format Unicode, j'ai pris soins d'activer le drapeau u en plus de e afin que l'encodage soit pris en compte par la fonction.

Les plus attentifs auront certainement remarqué que nous venons de résoudre simultanément les problèmes posés par les étapes 3 et 4.

Il ne reste donc plus qu'à trouver une solution pour le problème posé par l'étape 2.

En parcourant Internet, j'ai trouvé différentes solutions, plus ou moins immondes, et les plus intéressantes étaient basées sur intl.

Mon contexte de mise en œuvre étant strictement limité au français, j'ai décidé de me baser sur ces dernières en les simplifiant fortement.

La logique de fonctionnement est basée sur la normalisation des chaînes Unicode, qui consiste, en très résumé, à remplacer, par exemple, le caractère Unicode é par la combinaison des caractères e et ́ dans la chaîne considérée.

Une fois cela réalisé, il ne suffit donc plus que de supprimer les caractères Unicode ajoutant l'accentuation pour obtenir une chaîne sans le moindre accent.

Pour cela, preg_replace() est une nouvelle fois mis à contribution, via les propriétés des caractères Unicode.

Une fois tout cela combiné, on obtient le magnifique code suivant :

<?php $string = lcfirst(preg_replace('/\s+(.)/ue', 'ucfirst(\'\\1\')', preg_replace('@\pM@u', '', \normalizer::normalize(trim($string), Normalizer::FORM_D)))); ?>

Et si l'on aime le beau code, comme moi, il est possible de pousser l'esthétique jusqu'à cela :

<?php $string = preg_replace(array('@\pM@u', '/^(.)/ue', '/\s+(.)/ue'), array('', 'lcfirst(\'\\1\')', 'ucfirst(\'\\1\')'), \normalizer::normalize(trim($string), Normalizer::FORM_D)); ?>

<ironie>Finalement, Unicode, ça peut servir !</ironie>

[MAJ] Suite à la parution de ce qui précède, il m'a été proposé d'autres solutions, la plupart reposant sur iconv.

Dans un premier temps, je ne les avais pas prise en compte, car je pensais que cette extension n'était pas native au langage, au contraire de intl, ce qui aurait été un problème dans mon contexte de mise en œuvre.

Or, après vérification, iconv est bien livrée en standard avec PHP, et elle a l'avantage de permettre la gestion de tous les alphabets, puisqu'elle permet la conversion d'une chaîne de caractère Unicode vers l'ASCII.

Voici donc une solution basée sur cette extension, conçue à partir de la proposition de Maître Yoda :

<?php $string = lcfirst(preg_replace('/\s+/u', '', ucwords(strtolower(iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', trim($string)))))); ?>