Change out put of the_post_thumbnail in PHP

Filters are WordPress not PHP.

Second, you have called the thumbnail_filter function. You hooked it to post_thumbnail_html so any time a function runs that applies that filter, like the_post_thumbnail, your function runs. If you think about that, you will see that you have a bit of a Loop there. The filter calls a function (twice) that applies the filter.

Third, the_post_thumbnail will echo the image. That is not what you want. And I am a bit confused about what these two lines (not counting the comment)…

the_post_thumbnail($default_attr);
// you can alter the resulted HTML here
$html = the_post_thumbnail($default_attr);

… are meant to do.

I think you are somewhat confused about how filters work.

This particular filter passes several parameters:

return apply_filters( 'post_thumbnail_html', $html, $post_id, $post_thumbnail_id, $size, $attr );

You only need the first for what you are doing. You need to alter that input and return it, like so:

function thumbnail_filter($html) {
  $pattern = '|src="https://wordpress.stackexchange.com/questions/107950/([^"]*)"|';
  $html = preg_replace($pattern,'src="/absolute/loading/gif/path.gif" source="$1"',$html);
  return $html;
}
add_filter('post_thumbnail_html', 'thumbnail_filter');

Please be sure to use the absolute URL for your loading gif by using a function like get_stylesheet_directory_uri, or whatever is appropriate in your case. Do not use a relative URL. It will cause trouble.