-
Notifications
You must be signed in to change notification settings - Fork 668
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
Extra keys cause InvalidArgument #8744
Comments
I found these snippets: https://psalm.dev/r/f7ad4bc37e<?php
/**
* @param array{message: string}|null $error
*/
function outputMessage(?array $error): void
{
if (!$error) {
return;
}
echo $error['message'];
}
outputMessage(error_get_last());
|
Starting from Psalm v5, arrays will be sealed by default to avoid unexpected bugs, remove false positives and false negatives and improve overall type inference with more and better assertions. |
Thank you for the quick response and the pointer! Okay wow… This will break a lot of well annotated projects out there. I fully understand the problem that you want to solve, but I'd appreciate it if we could think about a friendlier way forward. Could we at least get a more specific error that a generic |
Another idea could be to introduce a new |
See #8701 |
The majority of projects making use of shape annotations can easily use type aliases to re-use shapes passed around codebases. The specific example posted in this issue is one of the rare cases where Always use sealed array shapes for userland code, and I may come up with a way to reference to array shapes of native functions in a future PR (maybe even by directly providing a set of native type aliases for commonly used shapes in the PHP STL, though this is really a bit of an edge case IMO :) |
The Psalm 5 announcement post will discuss this in detail, and I hope issues with unsealed shapes being passed where sealed shapes are expected will be minor. As for having a specific issue for this, it’s an interesting idea, but the better option is to have an error message that explicitly shows which fields are missing in error messages (vs leaving it up to the user). That will hopefully be added soon! |
At least on the codebases where I tested Psalm 5 on, this change is a major source of "new" errors. And in most cases, the affected code parts look like my example: A function declares an array shape as input parameter with only the keys it actually reads from. It does not care much about extra keys and it's not confused by them either. No And this is the dilemma I find myself in: This change results in many false-positive errors in codebases that have documented their array shapes thoroughly already. Authors are force to revisit all the doc blocks they've written over the last months/years with the non-sealed behavior in mind. This causes a lot of busy work that might even block an update. Improving the error message would be good as well because currently those are unreadable on big array shapes. Then again, my problem is not that I don't understand the errors. It's that I have so many of them on a perfectly fine codebase. Right now, I would have to suppress all of them in order to upgrade to Psalm 5. And So again, either of those option would be a big help for me:
|
That's kind of the point of a breaking change in a major release, authors will have to revisit their code to account for the new behavior :) Anyway, the fact that your codebase has a bunch of shape-related InvalidArgument errors is symptom of the fact that you're not reusing shapes properly via type aliases (and/or DTOs are not being used nearly enough). Today @ work I'll start migrating our large codebase to sealed-by-default shapes: I already know I'll have some ~500 issues, but I already know that the majority of them can be easily fixed by defining some ~10-20 type aliases, and by using DTOs instead of arrays with Valinor. It'll probably take a day or two of work, but the benefits especially from the reduced false positives in assertions and the exclusion of an entire class of foreach, join and shape->generic array bugs are much larger compared to the relatively small migration effort. |
Perhaps we could make conversion from sealed arrays to eg |
Thanks a lot for your input @derrabus ! We're aware that this change will imply work in codebases. Do you have an idea about how many issue this can represent for known repos? One thing to note too is that a lot of errors will probably be fixed by changing a single signature so it may appear more impressive than it really is I like the idea of a Psalter fix too, but it would be a shame if everyone just added |
No, I am sorry, but it is not. It is okay of course to introduce breaking changes, but not for the sake of breaking things or keeping people busy. I do accept breaking changes, but what I'm trying to discuss here is a way to make the way forward a less painful one.
Also this: I did not come here for a lecture. I am aware that the codebases I'm working on are not the pinnacle of modern software design. Most of those codebases are legacy code that use associative arrays way more than they should. And those arrays change their shape all the time which is why working with type aliases does not get me far. Rest assured that I am constantly addressing this kind of issues in my projects. And I am very happy that the developers I'm working with slowly adopt static analysis and document their array shapes. The possibility to document array shapes enabled them to use static analysis on code that seemed inaccessible to automated quality tools. This is really wonderful! But I am certain that the very same developers will be most frustrated when upgrading to Psalm 5 if the change is shipped as I experience it in the RC. Imagine developers thoroughly documenting input parameters to legacy functions whenever they needed to understand and change them, with exactly the syntax that Psalm supports. And suddenly they upgrade to a new version and that very same tool tells them that all their documented types are broken because they should've used a syntax that the old version didn't even understand to fix a problem that the old versions wasn't even remotely aware of. I repeat: I understand the reasoning behind sealed array shapes and I do believe using them will improve the quality of errors reported by Psalm. But please give me a painless way to progressively adopt the change. I have made two proposals on how this could be achieved.
Thank you for taking the time! 🙂
You are probably referring to the Doctrine repos, but there's also proprietary code I work on for my clients (because working on Doctrine won't pay my bills unfortunately 😉). This is mostly legacy stuff that I did not write myself and I mainly use static analysis there to regain control over old code with poor test coverage. And the developers that maintain those codebases are fairly new to static analysis. I can certainly explain to them why sealing array shapes is probably a good idea. Think about mistyped array keys when adding values to an array, that have gone unnoticed previously. But as I said, give them a way to iteratively adopt the concept.
They certainly will and I hope I have made myself clear that I don't question the benefits of the sealed array shape feature.
I have no idea how to measure that, I'm afraid.
An automated fixer would certainly help as well. Could be an alternative to the two options I've mentioned earlier. |
Be aware that currently PHPStan (and certainly phpstorm) doesn't support An option to keep considering
as unsealed would have help for the transition v4-v5 and the compatibility with other tool. |
There is are big differences between BC-break in code, and BC-break in phpdoc. The Phpdoc is shared between multiple tools: Psalm, PHPStan, Phpstorm, ... If, as a psalm 5 user, I use a library which still annotate the code with Psalm 4, I'll get multiple false positive. Having at least an option to control the meaning of |
Found while testing 5.0.0-rc1
https://psalm.dev/r/f7ad4bc37e
This function expects an array with a
message
key. I'm passing an array that has that key among others. Yet, I'm getting anInvalidArgument
error. That feels like a false positive.The text was updated successfully, but these errors were encountered: