PHP's date functions work with dates not strings. And that's an important distinction. Strings are just a bunch of characters in a specified order. Dates have months, days, years, hours, minutes, seconds, timezones, etc. When PHP works with dates it takes all of them into consideration.
So when you pass Feb 31 to a PHP date function it is going to try to make sense of it as a date and not a string. This means it isn't just going to take that date cut it up into bits and then rearrange them as you are expecting. It is going to turn that date into a date representation it can work with and then manipulate it.
As we all know, February does not have 31 days. As a result of the invalid date, PHP is trying to be helpful and taking three days after last day in February of that year (since Feb only has 28 days this year) and giving you that date.