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
Property not set in constructor when using trait in abstract class #6087
Comments
I found these snippets: https://psalm.dev/r/5a9fe1453e<?php
trait FooTrait {
protected \DateTimeImmutable $creationDate;
public function getCreationDate(): \DateTimeImmutable {
return $this->creationDate;
}
protected function initTimestamp(\DateTimeImmutable $creationDate): void {
$this->creationDate = $creationDate;
}
}
abstract class Foo {
use FooTrait;
public function __construct(\DateTimeImmutable $creationDate) {
$this->initTimestamp($creationDate);
}
}
class Bar extends Foo {
}
https://psalm.dev/r/13cce84db7<?php
trait FooTrait {
protected \DateTimeImmutable $creationDate;
public function getCreationDate(): \DateTimeImmutable {
return $this->creationDate;
}
protected function initTimestamp(\DateTimeImmutable $creationDate): void {
$this->creationDate = $creationDate;
}
}
class Bar {
use FooTrait;
public function __construct(\DateTimeImmutable $creationDate) {
$this->initTimestamp($creationDate);
}
}
|
Issue is still present event with an explicit call to |
I found these snippets: https://psalm.dev/r/f177e0b295<?php
trait FooTrait {
protected \DateTimeImmutable $creationDate;
public function getCreationDate(): \DateTimeImmutable {
return $this->creationDate;
}
protected function initTimestamp(\DateTimeImmutable $creationDate): void {
$this->creationDate = $creationDate;
}
}
abstract class Foo {
use FooTrait;
public function __construct(\DateTimeImmutable $creationDate) {
$this->initTimestamp($creationDate);
}
}
class Bar extends Foo {
public function __construct(\DateTimeImmutable $creationDate) {
parent::__construct($creationDate);
}
}
|
It seems related to #4393 |
The issue is valid because descendants can override |
I found these snippets: https://psalm.dev/r/1041e80bc6<?php
trait FooTrait {
protected DateTimeImmutable $creationDate;
public function getCreationDate(): \DateTimeImmutable {
return $this->creationDate;
}
protected final function initTimestamp(\DateTimeImmutable $creationDate): void {
$this->creationDate = $creationDate;
}
}
abstract class Foo {
use FooTrait;
public function __construct(\DateTimeImmutable $creationDate) {
$this->initTimestamp($creationDate);
}
}
class Bar extends Foo {
}
|
You probably would need to make the constructor final too, but the issue is still present there too: https://psalm.dev/r/e0c6c4b20f Maybe the analysis should change approach and determine if the call sequence in any class does end with the initialization of such properties.. |
I found these snippets: https://psalm.dev/r/e0c6c4b20f<?php
trait FooTrait {
protected DateTimeImmutable $creationDate;
public function getCreationDate(): \DateTimeImmutable {
return $this->creationDate;
}
protected final function initTimestamp(\DateTimeImmutable $creationDate): void {
$this->creationDate = $creationDate;
}
}
abstract class Foo {
use FooTrait;
public final function __construct(\DateTimeImmutable $creationDate) {
$this->initTimestamp($creationDate);
}
}
class Bar extends Foo {
}
|
I've also been having this issue when attempting to write a Psalm plugin for Doctrine ODM for MongoDB. It's slightly different, as the constructor itself is in the trait, but the error is the same. Example: https://psalm.dev/r/0f71ca2564 |
I found these snippets: https://psalm.dev/r/0f71ca2564<?php
class DocumentRepository {
public string $foo;
public function __construct(string $foo)
{
$this->foo = $foo;
}
}
trait ServiceRepositoryTrait {
public function __construct()
{
parent::__construct('hello world');
}
}
abstract class ServiceDocumentRepository extends DocumentRepository {
use ServiceRepositoryTrait;
}
class MyRepository extends ServiceDocumentRepository
{
}
|
No, the issue is not valid. There is no can in "descendants can override". A descendant either does initialize the |
I found these snippets: https://psalm.dev/r/1041e80bc6<?php
trait FooTrait {
protected DateTimeImmutable $creationDate;
public function getCreationDate(): \DateTimeImmutable {
return $this->creationDate;
}
protected final function initTimestamp(\DateTimeImmutable $creationDate): void {
$this->creationDate = $creationDate;
}
}
abstract class Foo {
use FooTrait;
public function __construct(\DateTimeImmutable $creationDate) {
$this->initTimestamp($creationDate);
}
}
class Bar extends Foo {
}
|
Are there any additional test cases or anything else that would help with this issue? I'd like to contribute but have next to no understanding of how Psalm's internals work. |
Mainly we need contributors with a good understanding of how Traits works. I barely use them myself so I'm not very motivated to dig into this subject on top of being almost ignorant about the syntax and how people use them. If you want to take a shot, you can try following those instructions: #6937 (comment) and report your findings, we'll try to help if you get stuck |
I think I've found a strange behaviour, in this snippet psalm complains about a property not set in constructor when the concrete class extends an abstract class using a trait.
https://psalm.dev/r/5a9fe1453e
If I take rid of the abstract class everything is fine.
https://psalm.dev/r/13cce84db7
It's a bug?
The text was updated successfully, but these errors were encountered: