Sous Windows, CreateProcess ne retourne en fait pas de code d'erreur. Au lieu de cela, vous utilisez GetLastError pour trouver plus de détails si CreateProcess échoue, puis utilisez FormatMessage pour transformer le code d'erreur de GetLastError en une description appropriée. (Les codes d'erreur de GetLastError peuvent également être décodés en utilisant cette liste)
En regardant le code source de proc_open(), PHP fait en fait le GetLastError() pour vous en cas d'échec, et le code d'erreur qui est enregistré est le retour de GetLastError() plutôt que de CreateProcess (qui renvoie un BOOL, peu probable d'être 3 :) )
Remarquez que proc_open utilise ceci pour afficher le message :
php_error_docref(NULL TSRMLS_CC, E_WARNING, "CreateProcess failed, error code - %u", dw);
...donc le "-" que vous avez avant le 3 est juste un trait d'union, pas un signe négatif. Vous obtenez donc le code d'erreur 3, qui, selon cette liste signifie "Le système ne trouve pas le chemin spécifié".