1
0
mirror of https://github.com/danog/psalm.git synced 2024-12-10 15:50:26 +01:00
psalm/docs/running_psalm/issues/UnsafeGenericInstantiation.md

158 lines
2.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# UnsafeGenericInstantiation
Emitted when an attempt is made to instantiate a class using `new static` without a constructor that's final:
```php
<?php
/**
* @template T
* @psalm-consistent-constructor
*/
class Container {
/**
* @var T
*/
public $t;
/**
* @param T $t
*/
public function __construct($t) {
$this->t = $t;
}
/**
* @template U
* @param U $u
* @return static<U>
*/
public function getInstance($u) : static
{
return new static($u);
}
}
```
## Whats wrong here?
The problem comes when extending the class:
```php
<?php
/**
* @template T
* @psalm-consistent-constructor
*/
class Container {
/**
* @var T
*/
public $t;
/**
* @param T $t
*/
public function __construct($t) {
$this->t = $t;
}
/**
* @template U
* @param U $u
* @return static<U>
*/
public function getInstance($u) : static
{
return new static($u);
}
}
/**
* @extends Container<string>
*/
class StringContainer extends Container {}
$c = StringContainer::getInstance(new stdClass());
// creates StringContainer<stdClass>, clearly invalid
```
## How to fix
Either use `new self` instead of `new static`:
```php
<?php
/**
* @template T
* @psalm-consistent-constructor
*/
class Container {
/**
* @var T
*/
public $t;
/**
* @param T $t
*/
public function __construct($t) {
$this->t = $t;
}
/**
* @template U
* @param U $u
* @return self<U>
*/
public function getInstance($u) : self
{
return new self($u);
}
}
```
Or you can add a `@psalm-consistent-templates` annotation which ensures that any child class has the same generic params:
```php
<?php
/**
* @template T
* @psalm-consistent-constructor
* @psalm-consistent-templates
*/
class Container {
/**
* @var T
*/
public $t;
/**
* @param T $t
*/
public function __construct($t) {
$this->t = $t;
}
/**
* @template U
* @param U $u
* @return static<U>
*/
public function getInstance($u) : static
{
return new static($u);
}
}
/**
* @template T
* @psalm-extends Container<T>
*/
class LazyLoadingContainer extends Container {}
```