On Mon, Oct 17, 2022, at 12:33 PM, Tim Düsterhus wrote:
>>> Okay, now the Exception message changed. Personally I do not consider
>>> this a BC break: I believe Exception messages are meant for human
>>> consumption, not for programs. Otherwise fixing a typo in the message
>>> would be a BC break. If the code wants to learn about the cause, it
>>> should either use the '$code' or different types of Exception should be
>>> thrown to clarify the cause by entering a different catch() block.
>>>
>>
>> Yes, the specific error message should be part of the BC promise. This
>> allows building test suites that can assert the message in a stable way.
>
> I'm not talking about test suites here. I believe makes sense to verify
> the error message to ensure a specific error message is emitted to the
> human observer in the error log.
>
> I was talking about code that does something like this, which I consider
> to be inherently unsafe:
>
> try { … }
> catch (SomeException $e) {
> if ($e->getMessage() === 'Foobar') doSomething();
> else doSomethingElse();
> }
>
> As a library author I want to be able to provide the best possible
> Exception message to ease debugging for the user. This is not possible
> if I am locked into a bad choice forever.
Just to be clear, such code is sometimes necessary. If the exception doesn't
include sufficient information as dedicated properties, parsing out the string
becomes the only option. I've had to do this myself.
In 100% of cases, without exception (no pun intended), that's because the code
that throws the exception is bad and wrong and should be fixed. But such code
absolutely exists in the wild, including in php-src. I recently needed to
sscanf() and then explode the message of \ArgumentCountError as that was the
only way I could find to get the class/method names out of it. I died inside a
little.
So yes, such code is inherently unsafe, but is sadly not as uncommon as it
should be.
All that said, I agree that we have not and should not treat error message
strings as part of the API guarantee. If anything, maybe that will help
incentivize people to stop writing bad (unparsable) exceptions.
Which I think gets at the crux of the issue here, and what is often the issue
in BC discussions.
PHP does not, and has never, guaranteed full BC for all code. It has tried
very hard to maintain BC for "well-behaved code." Well-behaved code can
generally update to a new version, even a new major, very easily with minimal
work. Any deprecations are alerted at least a year in advance, sometimes
several, and usually have easy-to-automate transitions that tools like Rector
can implement. (The discussion about deprecations being "too noisy" in some
tooling is another matter that has been hashed out before, so I won't belabor
it here.) Code that is following common best-practices rarely has an issue.
The problem is that "well-behaved" is not well-defined. Is relying on an error
message string well-behaved? I'd argue no, but as noted above sometimes
there's no better option. Others may disagree. Is relying on the exact
exception class thrown well-behaved? Well... sometimes. Is relying on an
error condition being swallowed rather than turning into an exception
well-behaved? I could argue either way here, honestly. Is code relying on
undefined variables silently becoming null well-behaved? Absolutely not, and
hasn't been for a decade, but it wasn't until PHP 8.0 that the language called
people out for it by default, so many projects had a lot of catch up to do.
(Eg, I did that catch up for TYPO3.)
I don't know that we can make a clear definition of "well-behaved" that
everyone could agree on. It would be nice, but it's a very squishy topic. But
it may be prudent, when not tied down to this specific RFC, to have a broader
discussion about better codifying (meaning, writing down) what we consider a BC
break and what we don't, what some heuristics are for "well-behaved," and so
on. That could help avoid, or at least shorten, a lot of discussions in the
future.
--Larry Garfield
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php