Long story short: foo($x) passes the variable $x, not its value. If something changes $x before foo uses what's passed, foo will see the change. If you want to pass a value, pass "$x", 0+$x, or the like.
Whenever you see a global variable (particularly those that change as a side-effect, such as $@, $?, $!, $<digit>) passed (rather than its value), your code smell alarm should go off.