-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Fixed typing for Symfony\Component\Validator\Constraint::$groups #45208
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
Null is not allowed actually. The only place where we have |
This change looks wrong to me. Passing |
<?php
include_once __DIR__ . '/vendor/autoload.php';
class MyConstraint extends \Symfony\Component\Validator\Constraint
{
public function __construct()
{
var_dump($this->groups);
}
}
$c = new MyConstraint();
var_dump($c->groups); |
This use case is broken, not calling the parent constructor is not supported. |
@zerkms when you create a custom constraint, you must call the parent constructor. Otherwise, the initialization of the class is not complete, and things are in a broken state. |
How would one write statically analysable code then:
This as expected fails with
At the moment annotation says: |
How about
for the |
@zerkms failing where ? If this is about psalm or phpstan, this is a false positive from those tools, that don't understand the lazy initialization done in |
it's not false-positive: class properties managed by magic methods should be declared as |
The property is already declared on L66. Please open a bug report on your favorite SA instead. |
declaration on line 66 is a lie. Take |
<?php
include_once __DIR__ . '/vendor/autoload.php';
class MyConstraint extends \Symfony\Component\Validator\Constraint
{
}
var_dump(get_object_vars(new MyConstraint())); it outputs
So, how I don't disagree that code works, but typing there is a lie and it is has nothing to do with SA. |
At this stage, it is in "uninitialized" state. |
@zerkms |
A constructed object must be fully initialised, that's what @stof said above. |
right, but there is no |
I understand you now would protect the current solution no matter what, but current implementation is a dirty hack, that wouldn't be possible to implement in a statically strictly typed language like Rust or even Java. |
@nicolas-grekas it's absolutely impossible to type
|
Well, I understand this is complex, but there is a reason for the current design (laziness), and the current way is the only way. Here, I really think this is something that should be improved on the SA's side. The code in Constraint is unusual, but perfectly legit. |
Why not accept suggesed @property string[] $groups ? phpdoc designed it for exactly this use case.
it's really impossible: I can override Types should be statically verifiable. |
Oh,
/**
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
* @property int $maxSize
*
* @author Bernhard Schussek <bschussek@gmail.com>
*/ |
@zerkms when you use the object API, you will never get The
if you override the The issue with SA tools is that today, the way they deal with the uninitialized state that exists in PHP is to enforce initialization in the constructor, instead of enforcing initializing it before usage. That's a shortcut they took to simplify their analysis, but it means that those tools are rejecting perfectly valid code. and that's an issue of the SA tool, not of Symfony.
that's totally different. In this class, we indeed rely on a magic public property. In Constraint, the public property is already the declared one being lazy-initialized. |
oh, come on: it's defined as a field there too: If the culprit is having it public vs protected: can we please have |
you just made this rule up to prove your point. Nothing in php requires overridden magic methods to always call parents.
It's not a shortcut: static analysis is called static because it's done statically, while current |
I fail to see how a PHPdoc improves typing. For PHP, it's just a comment so your code is just as typesafe. For non-code, the property is defined as public, so it can be argued that it's rather a limitation from the SA side to not detect this use-case properly (given it was also defined in the RFC).
Please try to not be offended and maybe close this tab for an hour and take a breath of fresh air. We're just discussing code here, not persons or people (we all don't know eachother, so we can't judge anything about anyone personally). Overriding a method is always changing behavior of a parent method, if you don't change behavior you wouldn't need to override it. In the case of this class, overriding |
that's correct, but it should not break API: if you declare a field as Overriding a method should not break typing of an irrelevant field. Code is either statically analysable or not: at the moment Try to design the same class in Java or Rust - how would it look? |
It's unlikely anybody will post here now, so I will summarise myself: The current implementation is done that way to be a performance optimisation and it makes it really impossible to statically analyse it. Because typing relies on runtime and php semantics don't guarantee the field to be of specified type. I understand you are tied to code you designed and implemented (me too - to mine), but just accepting that "code is not ideal and it's not statically analysable" would be a much better answer than blaming SA tools imperfection. Update: after a long and useful chat with @nicolas-grekas in the symfony slack they could provide a valid path for an extremely advanced (and not existing) SA to be able to verify the declarations statically (it's unfortunate that it will never exist, but at least it was convincing that it's really possible to verify at least theoretically). |
Linking to #44854 for reference. |
At the moment it's typed as
string[]
while in fact it'sstring[]|null
.