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
[Bug]: Class template property is checked against the template name when the constructor is inherited from a non-generic parent #112
A class declares @template TEntity and a property @var TEntity. If the class's constructor is inherited from a parent above it (a parent with no @template), assigning anything to the property fails as if TEntity were a class name:
Property App\TextField::$entity must be of type TEntity, stdClass given
TEntity is unbound, so any value should be accepted (PHPStan treats it as mixed). Move the constructor into the templated class, or remove it, and the same assignment passes.
This is a different trigger from #104 (fixed in v0.11.2): #104's repro has no constructor and passes on 0.11.3; whether the declaring class is inside include does not matter here, the repro fails with everything included.
Playground
Open in playground — output: Property App\TextField::$entity must be of type TEntity, stdClass given
Property App\TextField::$entity must be of type TEntity, stdClass given
Expected
construct/assign: OK
Controls
Any one of these makes it pass:
delete Base::__construct;
move the constructor into Field (the class that declares @template TEntity);
redeclare __construct in TextField.
The InputField middle class is not needed (TextField extends Field also fails); it is there because that is the shape we hit.
Where it seems to come from
InlineChecker::checkProperty() asks propertyUsesTemplates() / substitutePropertyGenerics(), which read the class templates through DocblockParser::parse($className . '::__construct')['classTemplates']. For an inherited constructor, parseMethod() takes the target class from $ref->class, i.e. the class that declares__construct (Base), which has no templates. classTemplates comes back empty, the template is not substituted, and the validator resolves TEntity as a class. Passing the requested class into parseMethod() (or reading the templates with the class-level parser instead of via the constructor) fixes the repro locally.
Versions
v0.11.3 and dev-main @ 4e4244e (local project, PHP 8.3), and the playground.
Context
Our framework's base component class owns the constructor; every form field extends it through a @template TEntity field base, so every $field->entity = $entity in checked code reports a violation (about 200 per module run).
Activity