If a parameter (hash key) might not exist, then the exists() function should be used to test for this possibility. Unlike defined(), this function will check to see if the key exists, no matter what the associated value is. (A key containing the value undef exists, but it is not defined.)
Incidentally, if the parameter truly is “optional,” I would recommend that the caller should omit the parameter entirely, rather than provide any sort of sentinel value – e.g. undef or zero – in its place. exists() will then be able to tell you if the parameter was provided or not. Should you find that the value exists but that it is nonsensical, I recommend that your routine should throw an exception.