-
Notifications
You must be signed in to change notification settings - Fork 13
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
feat(DowngradePhp73JsonConstRector): throw behavior #133
Conversation
* add a code sample for `json_decode`
* Try to properly downgrade the throw behavior removed from `json_encode` and `json_decode` with an alternative code snippet added after the function node. * This is a partial solution that only handles when the flags are directly set in the function call.
a37bbd1
to
63abfb6
Compare
@samsonasik It seems there's a problem in your CI when the PR branch is not from the main repository, so the last check can't pass. |
You can run |
@samsonasik following your advice, the code is fixed for the CI, but I had also to fix one file outside of the scope of this PR, which was not reported locally. |
You need to enable |
It seems I'm unlucky today, everything was finally fine but some packages got an update and a lot of things are now broken (that are not related to this PR)
|
It seems new phpstan cause error in rector-src as well:
I will check if that possibly related. |
I created PR: for it. |
Thanks @samsonasik and @TomasVotruba for the fix on rectorphp/rector-src |
@TomasVotruba the error:
because BetterStandardprinter doesn't have |
I create new PR for extends PHPStan printer instead: |
Let see if rectorphp/rector-src#4310 resolve the rector build, let's restasrt build... |
CI seems green now 👍 |
@samsonasik awesome, thanks 🙏 I hope my contribution could be useful and merged if you think so. |
Thank you for contribution 👍 lets give this a try |
It seems cause downgrade build error https://github.com/rectorphp/rector-src/actions/runs/5332525439/jobs/9664202507 I will look into it. |
$funcCall = match ($stmtExpression->expr::class) { | ||
Assign::class => $stmtExpression->expr->expr instanceof FuncCall | ||
? $stmtExpression->expr->expr | ||
: null, | ||
FuncCall::class => $stmtExpression->expr, | ||
default => null, | ||
}; |
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.
downgrade this part seems cause error: https://github.com/rectorphp/rector-src/actions/runs/5332525439/jobs/9664202507#step:15:72
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.
The error seems happen on php 7.4 https://3v4l.org/75qT2#v7.4.33
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 think it is because The scope of $stmtExpression->expr
is already lost as parent re-printed, the better solution I think is refactor the code for now. I will create new PR.
I think for inside try-catch, it should use the the catch stmts, see rectorphp/rector@3236151#diff-3730c571f73f17d036e1d2177280cdb16a21772965d08ad48f23485036b9b03a should be: try {
- $resource = \json_encode($resource, \JSON_THROW_ON_ERROR);
+ $resource = \json_encode($resource, 0);
if (\json_last_error() !== \JSON_ERROR_NONE) {
- throw new \Exception(\json_last_error_msg());
+ $resource = \sprintf('resource of type "%s"', \get_debug_type($resource));
}
} catch (\JsonException $exception) {
$resource = \sprintf('resource of type "%s"', \get_debug_type($resource));
} |
or better, should be something like: - try {
- $resource = \json_encode($resource, \JSON_THROW_ON_ERROR);
+ $resource = \json_encode($resource, 0);
if (\json_last_error() !== \JSON_ERROR_NONE) {
- throw new \Exception(\json_last_error_msg());
+ $resource = \sprintf('resource of type "%s"', \get_debug_type($resource));
}
- } catch (\JsonException $exception) {
- $resource = \sprintf('resource of type "%s"', \get_debug_type($resource));
- } |
Hm.., I think inside try catch can just be skipped for add if after Expression to avoid regression, I will create new PR for it. |
if (json_last_error() !== JSON_ERROR_NONE) { | ||
throw new \Exception(json_last_error_msg()); | ||
} |
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 incorrect, as it previously on \Exception
to return false
, so must be skipped instead to avoid regression, so basically if inside try catch, it must not add the if, here the example:
with new behaviour, it throw exception, which should not.
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.
@samsonasik @TomasVotruba Not sure to follow you here, without the if
statement nor the JSON_THROW_ON_ERROR
, json_encode()
/ json_decode()
does not raise any error, so the catch
is not executed, that's exactly why this PR was made, you're actually removing the precise purpose of it.
The problem resides on the type of the exception thrown to match the one in the catch, you should not remove the if
entirely or you defeat the purpose of this PR and we are back to square one.
In PHP < 7.3 that does not throw (initial behavior of DowngradePhp73JsonConstRector
) :
https://3v4l.org/1Y2Bv#v7.2.34
try {
$data = "\xB1\x31"; // Invalid UTF-8 sequence (binary data)
$json = json_encode($data, 0);
echo $json;
} catch (JsonException $e) {
echo 'Error occurred during JSON encoding: ' . $e->getMessage();
}
While this replicate the same behavior as with JSON_THROW_ON_ERROR
(goal of my PR) :
https://3v4l.org/lb86Z#v7.2.34
try {
$data = "\xB1\x31"; // Invalid UTF-8 sequence (binary data)
$json = json_encode($data, 0);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new \Exception(json_last_error_msg());
}
echo $json;
} catch (Exception $e) {
echo 'Error occurred during JSON encoding: ' . $e->getMessage();
}
Also the exception JsonException
does not exist in PHP < 7.3 so your example is not valid in this context, if the catch specify a JsonException
, it should be replaced by a standard Exception
to be compatible with PHP < 7.3 anyway.
I could have worked that out if you didn't act so fast, with your last merge this PR is basically useless.
It was just needed a little bit of improvement on the exception type (and actually also handle the downgrade of JsonException
that I overlooked, thanks for pointing that out)
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.
See https://3v4l.org/k3U5V vs https://3v4l.org/gJkgE
Better approach to use catch stmts instead probably the real solution, but the quick fix is not add if to avoid regression.
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.
sorry, I don't get it, it's like you didn't read what I just said.
The 2 examples you just provided are not valid PHP 7.2.x (since JsonException
does not exist for that version)
https://www.php.net/manual/en/class.jsonexception.php
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.
Exception can be used, but need to map for what defined inside catch, or it will fatal error that mean regression.
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.
For rector use case, the downgrade is used to allow installed in php 7.2, to upgrade code from php 5 until php 8.2, so the downgraded code should keep working even opened in php 8.
I thought a "Downgrade" rule could only be applied.. well, for a downgrade. That wouldn't make much sense to apply it the other way around during an upgrade, but again I don't know all the subtlety of Rector.
Would be curious to understand it more, when you'll have the time, I have a few other PRs coming up 😅
I'll go with a custom local rule for now, since with your last changes it does not fix my downgrade problem anymore.
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.
as a side note, this can be rework with more carefull approach, with check if catch Exception or Throwable, or JsonException directly, then map the code below catch inside if, then remove the try catch itself.
See my comment above #133 (comment)
Yeah, I didn't get it at first tbh, but thing is you're trying to avoid the throw/catch entirely, while this is the initial/expected behavior of the code that should be retained, no matter what, else you get a discrepancy between the versions of your code.
I'll try to come up with something else if I have the time, unless you do it first. Thanks for your help and the discussion/debate 😉
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.
No worries, improvement is welcome, just need more carefull approach to avoid regression ;)
I have on list of downgrade improvement, one of them is patch invalid the docblock during downgrade, see rectorphp/rector#8004 but that's not our priority right now as docblock doesn't cause fatal 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.
No worries, improvement is welcome, just need more carefull approach to avoid regression ;)
btw, how could I have caught locally the regression issue you got before pushing the PR ?
Since all was green both locally and eventually in the CI, I don't know where to look for to reproduce it ?
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.
For this rule itself, for example, we have the following code:
try {
$data = "\xB1\x31"; // Invalid UTF-8 sequence (binary data)
$json = json_encode($data, JSON_THROW_ON_ERROR);
echo $json;
} catch (JsonException $e) {
echo 'something is wrong';
}
Currently, in php 7.3, it output something is wrong
, see https://3v4l.org/GkRKc#v7.3.33
When downgraded to php 7.2, it should keep show something is wrong
, see https://3v4l.org/XSJ4W#v7.2.34
This should limit per use-case to avoid general change,eg: Try, then catch JsonException, no finally, no anything else, if that works, we can improve to another improvement :)
Add a throwing error behavior after any
json_encode
orjson_decode
function called with theJSON_THROW_ON_ERROR
flag set, since it will be removed.This is a partial improvement of removing the
JSON_THROW_ON_ERROR
flag altogether without a proper alternative behavior, but that only works when the flags are directly set in the function call.If the flags are set from a variable, that would require a much more complex analysis to be 100% accurate, probably beyond Rector actual capabilities.