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
mixed template when implementing interface #4302
Comments
I found these snippets: https://psalm.dev/r/f3afaafff3<?php
/**
* @template T
*/
interface Collection
{
/**
* @param T $value
*/
public function add(string $key, $value): self;
}
/**
* @template T
* @implements Collection<T>
*/
class ArrayCollection implements Collection
{
/** @var array<string, mixed> */
private array $data = [];
/**
* @param array<string, mixed> $data
*/
public function __construct(array $data = [])
{
$this->data = $data;
}
/**
* @param mixed $value
*/
public function add(string $key, $value): Collection
{
$newData = array_merge($this->data, [$key => $value]);
return new self($newData);
}
}
/** @var ArrayCollection<string> $stringCollection */
$stringCollection = new ArrayCollection();
$stringCollection = $stringCollection->add('one', 1);
|
Widening a parameter type (aka parameter contravariance) is totally valid under LSP. interface I { public function add(string $value): void; } does not mean that the parameter should be string only. What it means is that any implementors must accept string. They are free to accept any type that is wider than string as well, e.g |
right! Thanks for the reply and the clarification! But what about the case when we have also a return type widening? for example https://psalm.dev/r/32966f69fa Here I would expect |
I found these snippets: https://psalm.dev/r/32966f69fa<?php
/**
* @template T
*/
interface Collection
{
/**
* @param T $value
*/
public function add(string $key, $value): self;
/**
* @return T
*/
public function get(string $key);
}
/**
* @template T
* @implements Collection<T>
*/
class ArrayCollection implements Collection
{
/** @var array<string, mixed> */
private array $data = [];
/**
* @param array<string, mixed> $data
*/
public function __construct(array $data = [])
{
$this->data = $data;
}
/**
* @param mixed $value
*/
public function add(string $key, $value): Collection
{
$newData = array_merge($this->data, [$key => $value]);
return new self($newData);
}
/**
* @return mixed
*/
public function get(string $key)
{
return $this->data[$key];
}
}
/** @var ArrayCollection<string> $stringCollection */
$stringCollection = new ArrayCollection();
$stringCollection = $stringCollection->add('one', 1);
echo $stringCollection->get('one');
|
This (https://psalm.dev/r/2bfe7193d0) should be flagged, as |
I found these snippets: https://psalm.dev/r/2bfe7193d0<?php
/** @template T */
interface Collection
{
/** @return T */
public function get(string $key);
}
/**
* @template T
* @implements Collection<T>
*/
abstract class ArrayCollection implements Collection
{
/** @return mixed */
abstract public function get(string $key);
}
|
Consider the code in https://psalm.dev/r/f3afaafff3
I would expect it to break since
$stringCollection
is an instance ofArrayCollection<string>
which implementsCollection<string>
. The latter says that the second parameter ofadd
should be astring
, while here I can actually pass anint
without any reported issuesThe text was updated successfully, but these errors were encountered: