You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Cannot set exception code for custom exception #14673
There is a note about default parameters in exception constructor on php.net. However, case 2 in the above example explicitly passes the code parameter to the constructor.
Calling the constructor of class Exception from a subclass ignores the default arguments, if the properties $code and $message are already set. about default parameters in exception constructor on php.net.
The code property is only updated if the value is not 0.
And that does not align with how all other classes in PHP work . Property values passed through constructor must always override default property values.
That's not really how it works. PHP is implementation-defined. This behavior is intentional and has been the same for 21 years. So, I consider this a wontfix, but let's see what others think.
I believe this behavior is not intentional. The documentation says that in this case the default arguments are ignored, but in practice it also ignores explicitly set argument when it's value is equal to zero, which is very confusing.
// This should return zero for any exception classes.
(newExample(code: 0))->getCode();
Note: Calling the constructor of class Exception from a subclass ignores the default arguments, if the properties $code and $message are already set.
Named arguments are relatively new. The default arguments refers to omitting the arguments, or providing the same value as the default explicitly. But again, PHP is implementation defined. When behavior and documentation diverge, behavior wins, unless it is obviously wrong. Even when it is obviously wrong, it's sometimes better to be cautious and not risk breaking old code, especially in patches. This could be discussed for master, but IMO is out of the question for stable versions.
It has nothing to do with named arguments.
This example may fail same way.
(new Example('', 0))->getCode();
The default arguments refers to omitting the arguments, or providing the same value as the default explicitly.
Well, that's not typical interpretation of "default arguments". In my opinion default arguments are those defined on the function signature, like int $code = 0.
unless it is obviously wrong.
That's what I am thinking about it. It obviously wrong.
To be very clear here, the behavior is totally intentional: if the $code parameter is non-zero then the constructor will set the property to that value. The internal code does something that translates to:
There's a little magic for the $message, unfortunately, but the behavior for $code is simple and obviously deliberate.
The implementation is the source of truth, so if the documentation doesn't accurately describe this behavior then it's the documentation that should be fixed.
Whether or not the implementation is "good" is a separate problem, however the behavior has been around for a long time - almost 21 years - so the question is whether there's sufficient reason to change it.
The code (which I suggest you look at, if you haven't yet) is based on whether $message is null - something only the internals can get away with since the signature is supposed to be string $message = "" and so null isn't supported as an actual value. The reason for null and the difference in behavior seems to be simply the result of various changes being made over a long time; I suspect the idea was to have it work like ?string $message = null but it didn't happen that way for whatever reason.
But that's not really the point. The point is that the constructor follows an unusual pattern, and that pattern has been in place for a long time, so it's highly likely (especially since it's somewhat documented) that some developers have been making use of it. Changes to that shouldn't be made on a whim.
I don't think that age of a bug should turn it into a feature.
Just because you don't like the behavior doesn't mean it's a bug.
Don't mistake me, I don't care for what it's doing either, and I also believe the constructor should work normally and anyone wishing to customize the message or code should do so by overriding the constructor. But me not liking the behavior either still doesn't mean it's a bug.
If you referer to that note on php.net that basically means that one of these parameters does not comply with this documentation. Which one depends on how you interpret the term "default arguments".
Just because you don't like the behavior doesn't mean it's a bug.
It's true. However, it's very confusing and it took me quite a lot time to figure out that this behavior comes from PHP internals not from my custom code.
Activity
iluuu1994 commentedon Jun 27, 2024
php-src/Zend/zend_exceptions.c
Lines 323 to 326 in a2cecd2
The
codeproperty is only updated if the value is not0. Changing this now would have some implications. E.g. this code would break:Instead of redeclaring the
codeproperty, why don't you override__construct()? This behaves the way you expected it to:Chi-teck commentedon Jun 28, 2024
And that does not align with how all other classes in PHP work . Property values passed through constructor must always override default property values.
iluuu1994 commentedon Jun 28, 2024
That's not really how it works. PHP is implementation-defined. This behavior is intentional and has been the same for 21 years. So, I consider this a wontfix, but let's see what others think.
Chi-teck commentedon Jun 28, 2024
I believe this behavior is not intentional. The documentation says that in this case the default arguments are ignored, but in practice it also ignores explicitly set argument when it's value is equal to zero, which is very confusing.
iluuu1994 commentedon Jun 28, 2024
For context:
https://www.php.net/manual/en/exception.construct.php
Named arguments are relatively new. The default arguments refers to omitting the arguments, or providing the same value as the default explicitly. But again, PHP is implementation defined. When behavior and documentation diverge, behavior wins, unless it is obviously wrong. Even when it is obviously wrong, it's sometimes better to be cautious and not risk breaking old code, especially in patches. This could be discussed for master, but IMO is out of the question for stable versions.
Chi-teck commentedon Jun 28, 2024
It has nothing to do with named arguments.
This example may fail same way.
Well, that's not typical interpretation of "default arguments". In my opinion default arguments are those defined on the function signature, like
int $code = 0.That's what I am thinking about it. It obviously wrong.
damianwadley commentedon Jun 28, 2024
To be very clear here, the behavior is totally intentional: if the $code parameter is non-zero then the constructor will set the property to that value. The internal code does something that translates to:
There's a little magic for the $message, unfortunately, but the behavior for $code is simple and obviously deliberate.
The implementation is the source of truth, so if the documentation doesn't accurately describe this behavior then it's the documentation that should be fixed.
Whether or not the implementation is "good" is a separate problem, however the behavior has been around for a long time - almost 21 years - so the question is whether there's sufficient reason to change it.
Chi-teck commentedon Jun 28, 2024
The current behavior for $message is what I expected for $code. It's intuitively clear and aligns with how all other PHP objects work.
Why $message and $code have different behavior?
I don't think that age of a bug should turn it into a feature. )
damianwadley commentedon Jun 28, 2024
The code (which I suggest you look at, if you haven't yet) is based on whether $message is null - something only the internals can get away with since the signature is supposed to be
string $message = ""and so null isn't supported as an actual value. The reason for null and the difference in behavior seems to be simply the result of various changes being made over a long time; I suspect the idea was to have it work like?string $message = nullbut it didn't happen that way for whatever reason.But that's not really the point. The point is that the constructor follows an unusual pattern, and that pattern has been in place for a long time, so it's highly likely (especially since it's somewhat documented) that some developers have been making use of it. Changes to that shouldn't be made on a whim.
Just because you don't like the behavior doesn't mean it's a bug.
Don't mistake me, I don't care for what it's doing either, and I also believe the constructor should work normally and anyone wishing to customize the message or code should do so by overriding the constructor. But me not liking the behavior either still doesn't mean it's a bug.
damianwadley commentedon Jun 28, 2024
Perhaps this should be added to the 8.4 deprecations/9.0 removal list?
Chi-teck commentedon Jun 28, 2024
If you referer to that note on php.net that basically means that one of these parameters does not comply with this documentation. Which one depends on how you interpret the term "default arguments".
It's true. However, it's very confusing and it took me quite a lot time to figure out that this behavior comes from PHP internals not from my custom code.
morrisonlevi commentedon Jun 29, 2024
I understand your desire to "fix" this, but do you have any issues with the work-around? Formatted for short lines: