-
-
Notifications
You must be signed in to change notification settings - Fork 9.7k
[PropertyAccess] Show property path in all exception messages #13294
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
👍 |
@@ -18,8 +18,4 @@ | |||
*/ | |||
class UnexpectedTypeException extends RuntimeException | |||
{ | |||
public function __construct($value, $expectedType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a bc break
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, it is a theoretical BC break, hence my note at the bottom of the original PR comment. I don't see a straightforward way around it:
- Using a new subclass of
UnexpectedTypeException
won't work because the constructor is already overloaded. - Using another exception class entirely would be a worse BC break.
- Adding optional constructor arguments might be a smaller BC break, but those arguments would make no sense when the exception is used in
PropertyPath
.
I can of course make some changes, or add the BC break notes, or scrap the PR entirely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest to
- change the exception in PropertyPath to
Symfony\Component\PropertyAccess\Exception\InvalidArgumentException
because that is more consistent with https://github.com/mpajunen/symfony/blob/property-access-exception-messages/src/Symfony/Component/PropertyAccess/PropertyAccessor.php#L57 and also makes more sense since it is a RuntimeException isntead of a LogicException (and should not be considered BC break since it's not intended to be catched). - adjust UnexpectedTypeException with optional extra params
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would work, I'll make the changes. Good point that the PropertyPath
exception is not meant to be caught anyway.
74f746b
to
7dd6de6
Compare
@@ -97,7 +97,12 @@ public function setValue(&$objectOrArray, $propertyPath, $value) | |||
|
|||
if ($overwrite) { | |||
if (!is_object($objectOrArray) && !is_array($objectOrArray)) { | |||
throw new UnexpectedTypeException($objectOrArray, 'object or array'); | |||
throw new UnexpectedTypeException(sprintf( | |||
'Expected object or array, "%s" found when trying to write property "%s" of path "%s".', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please change the message to PropertyAccessor requires a graph of objects or arrays to operate on, but it found type "%s" while trying to traverse path "%s" at property "%s"
.
Whether it's reading or writing is irrelavant at this point because it's always before doing so.
1fc18b4
to
cae6d4a
Compare
The messages have been changed. I also realized that using a new subclass of Could even revert the changes to |
public function __construct($value, PropertyPathInterface $path, $index) | ||
{ | ||
// Skip parent constructor. | ||
RuntimeException::__construct(sprintf( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this works? looks rather hackish
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it looks a bit hackish indeed. Seems to work well enough though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
call the parent constructor directly rather than using this hackish solution. It will be more robust when updating code. And then, trigger the error in the parent class only when using it directly:
if (__CLASS__ === get_class($this) {
trigger_error(...);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
He cannot call the parent constructor because the arguments are different.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, I missed that
If we go this route with a new subexception, then |
Alright, I can add the deprecation notes in that case. I think this approach produces the cleanest end result. The parent constructor skipping can eventually be removed when the deprecated To avoid similar problems in the future, it might be worth considering marking exception constructors internal, or using static factory methods, or avoiding custom constructors altogether. |
cae6d4a
to
7b5ecac
Compare
Deprecation comment and error added. Change log updated as well. Should I update the UPGRADE files as well (or even add a file for 2.7)? |
7b5ecac
to
2ca64e7
Compare
28f258e
to
de04059
Compare
Adding a new exception class just to deprecate the old one didn't really seem that forward compatible. So I refactored the changes to use If the user code throws |
Use InvalidArgumentException instead of UnexpectedTypeException since this exception is not meant to be caught.
Show the property path in the exception message when trying to access a property of an invalid variable.
de04059
to
1f2f272
Compare
Is there something more I can do to get this merged? (Rebased today.) |
looks good to me |
Thank you @mpajunen. |
…essages (mpajunen) This PR was squashed before being merged into the 2.7 branch (closes #13294). Discussion ---------- [PropertyAccess] Show property path in all exception messages | Q | A | ------------- | --- | Bug fix? | no | New feature? | no | BC breaks? | no | Deprecations? | yes | Tests pass? | yes | Fixed tickets | #12987 | License | MIT | Doc PR | N/A Add the property path to the exception message when trying to access a property of a scalar variable or null. For example: ```php $accessor->getValue((object) ['foo' => null], 'foo.bar'); // Throws UnexpectedTypeException $old = 'Expected argument of type "object or array", "NULL" given'; // Old message $new = 'PropertyAccessor requires a graph of objects or arrays to operate on, but it found type "NULL" while trying to traverse path "foo.bar" at property "bar".'; // New message ``` Checking the exception messages was added to the existing tests. ~~To make it possible to customize the exception messages, constructor was removed from `UnexpectedTypeException`. Instead the exception messages are built where the exception is thrown. (None of the other exception classes of the component had custom constructors.)~~ ~~There are no BC breaks -- unless removing the constructor of an exception class is considered one.~~ The original PR included a potential BC break but the structure was changed somewhat. The current version deprecates the old constructor for `UnexpectedTypeException`, but a BC layer is included. Commits ------- b286863 [PropertyAccess] Show property path in all exception messages
Add the property path to the exception message when trying to access a property of a scalar variable or null. For example:
Checking the exception messages was added to the existing tests.
To make it possible to customize the exception messages, constructor was removed fromUnexpectedTypeException
. Instead the exception messages are built where the exception is thrown. (None of the other exception classes of the component had custom constructors.)There are no BC breaks -- unless removing the constructor of an exception class is considered one.The original PR included a potential BC break but the structure was changed somewhat.
The current version deprecates the old constructor for
UnexpectedTypeException
, but a BC layer is included.