Hash jest zawsze inny, bo za każdym razem faktyczny input jest inny. Funkcja password_hash dla każdego hashowanego ciągu znaków generuje inną, unikalną sól (czyli dodatkowy ciąg znaków, dołączany na początek/koniec hashowanego tekstu).
Jak zatem to działa? Ha, sól jest po prostu zapisywana razem z hasłem i dzięki temu można odtworzyć to, co faktycznie zostało zahashowane (skrypt sam pobiera istniejącą sól, a user wpisuje hasło). Umożliwia to format MCF.
Natomiast nie rozumiem wątpliwości co do bezkolizyjności. Bezkolizyjność to fakt, że jedno hasło nie da takiego samego wyniku jak inne. To, że dla tego samego hasła (chociaż to nieprawda – patrz wyżej) zwracane są różne ciągi nie oznacza jeszcze, że algorytm jest kolizyjny.