Setting the response code implies setting a response header. These headers can only be set, as long as there is no output sent to the client.
To check, if you can add more http headers, you can use the function headers_sent.
In your example:
try {
throw new Exception('x');
} catch (Exception $e) {
echo '1 '; // If i comment this line, http status code will be 400...
if(headers_sent()) { //check if headers were sent already
print 'oops, headers have been sent already, not possible to add some more :-(';
}
http_response_code(400);
}
echo '3 ';
echo http_response_code();
On some servers, it is possible to echo a little amount of output, before the headers are finally sent. That happens, because an output cache of a certain size has been configured. (using the output_buffering setting)
So, it is very likely that this setting is set to 0 on your server. Then the headers are already sent with the first byte of output, even it is not visible.
More information can be found in an older question about sending headers and making some output: https://stackoverflow.com/a/8028987