NogDog;11034773 wrote:
For me, exceptions are for the sort of "unexpected behavior" that would result in a "WTF?" response, as opposed to, say, something that shouldn't normally happen but I can easily envision happening in some situations (e.g. bad user input). If my PDO::__construct() fails, that's probably a good candidate
PDO::construct should not fail, provided it's given reasonable input. Neither should User::construct() fail provided reasonable input. But just like PDO will throw an exception when it can't follow it's "ordinary program flow" or "give us what we asked for" (a new instance), so should User::construct throw.
Username validation is actually a good example. Common constraints: alphanumeric, max string length, unique. On new user registration, if you ask the database to check if there is already a user with $username, you get no error and no PDO exception. But if you try to store the user, you get a 22001 data truncated which leads to a PDO exception.
As far as probabilities goes, I'd say it's reasonable to expect a SQL-writing user to sooner or later execute a SQL query that will fail some constraint.
User::createFrom($data)
will return a user if provided user name is ctype_alnum, mb_strlen() < User::USERNAME_MAXLENGTH and no such user exists in the database. But if I fail to check either, I will most certainly expect PDO to throw no matter which of those checks fail. Consistently, from code calling User::isValid($newUserData), I would expect a simple true or false (or using validation of compound data, possibly indicating which entry(s) failed). But I would expect a call to User::create to throw.
You might to argue that User::createFrom will return a new instance, while User::store will fail. First off, I'd still say User::store should throw. Moreover, I'd claim it'd be reasonable for User::validate to either perform all validation right away (preferably -> leads to no invalid user instance ever existing), or leave all validation to store (or even the database, which is called from store), since that hopefully will not lead to coders assuming they can trust User instances to be valid.
Also note that [noparse]PDO::perpare[/noparse] will not throw for "SET someField = 'too long string'", because it's not an exception from this perspective. To prepare, it's a qestion of valid SQL code. But calling execute will lead to an exception, because from its point of vue there would be a violation of integrity.
It seems reasonable to define "exception" as being "exceptional to expected behaviour", since it leads to consistency in how to use them and how to regard them. Using a circular definition of what constitutes an "exception" as relating to its probability of occuring, instead seems like a rather good idea to throw one.