Character class range for the character range between two code points. The _ character is included in the Az range, and you can see this by looking at the ASCII table:
... YZ [\] ^ _ `ab ...
Thus, this is not only the underscore that is skipped, but also the other characters that you see above, as indicated in the documentation :
Ranges work in an ASCII sort sequence .... For example, [Wc] equivalent to [][\^_ ` wxyzabc] .
To prevent this from happening, you can perform case insensitivity with a single character range in your character class:
$name = preg_replace('/[^a-z0-9 ]/i', '', $str);
source share