L'appel à une fonction callback dans preg_replace est un casse-tête. Je préfère de loin preg_replace_callback().
De plus la fonction highlight_string() doit être bufférisée pour produire les effets désirés. Deux problèmes donc.
preg_replace avec
option e (qui manque dans ton exemple, il faut aussi rendre le multiplicateur + non gourmand):
$message = preg_replace('#\[php\](.+?)\[/php\]#ei', "'code html avant '.strtoupper('$1').' code html après'", $message);
La valse des quotes, et guillemets en trois temps!
Ici j'ai pris strtoupper() pour illustrer l'option e car, comme signalé plus haut, highlight_string() doit être bufférisée.
Dans ce contexte $1 n'est pas une variable mais bien une référence arrière à la sauce PHP. Equivalent à \1 dans les autres langages.
Essaye déjà ceci.
ripat