When listing a - within a character class, you can always put it as either the very first or very last character (in this case, since you have ^ to negate the class, make the - the second or last character). Or escape it otherwise with -
preg_match_all ( '/[^a-z0-9_ &-]/i' , $string , $matches );
Otherwise, you are creating a range (as in your version, a range from space to &... clearly not what you want).
Also note that a-z0-9 (case insensitive) can be summed up as \w. Granted, given your locale, \w may also match things like accented characters for example.. so you could ensure a pure a-zA-Z0-9 match like so:
setlocale(LC_CTYPE, 'C');
preg_match_all ( '/[^\w &-]/' , $string , $matches );
Edit - Do'h, Brad beat me to it.