我觉得问这么简单的问题很愚蠢,但我显然错过了一些基本的东西。
下面的 CollectionOrdered 类旨在“携带有效负载”,而 HasPayloadInterface 的目的是封装所有携带有效负载的类的操作,而不仅仅是 CollectionOrdered。
我有一个 CollectionOrderedFactory,它创建一个 CollectionOrdered 对象。我本以为工厂中 makeCollection 方法的返回类型将是 CollectionOrdered
但是
Phpstan 返回“makeCollection() 应该返回 CollectionOrdered
这是代码:
/**
* Class HasPayloadInterface
* @template PayloadType
*/
interface HasPayloadInterface
{
}
/**
* Class CollectionOrdered
* @template PayloadType of HasPayloadInterface
* @implements HasPayloadInterface<PayloadType>
*/
class CollectionOrdered implements HasPayloadInterface
{
}
/**
* Class CollectionOrderedFactory
* @template PayloadType of HasPayloadInterface
*/
class CollectionOrderedFactory
{
/**
* makeCollection
* @return CollectionOrdered<PayloadType>
*/
public function makeCollection(): CollectionOrdered
{
return new CollectionOrdered();
}
}
预先感谢您的一些指导。
我可以在您的代码中看到两个问题:
PayloadType
指的是通用接口HasPayloadInterface
,但其类型未指定:/**
* Class CollectionOrdered
* @template PayloadType of HasPayloadInterface
* @implements HasPayloadInterface<PayloadType>
*/
class CollectionOrdered implements HasPayloadInterface
如果我们用
PayloadType
代替它的值,我们将得到:@implements HasPayloadInterface<PayloadType of HasPayloadInterface>
。在此表达式中,显然缺少第二个对 HasPayloadInterface
的引用的类型参数。如果我们添加缺失的类型,我们会得到这样的结果:
@implements HasPayloadInterface<PayloadType of HasPayloadInterface<PayloadType>>
但是
PayloadType
属于 HasPayloadInterface,
,所以我们最终得到了循环引用。
我猜你的代码中可能有错字。相反,我希望看到有效负载的单独类型,例如:
/**
* @template PayloadType of string
* @implements HasPayloadInterface<PayloadType>
*/
class CollectionOrdered implements HasPayloadInterface
PayloadType
推导出为 HasPayloadInterface
之外的任何内容:/**
* Class CollectionOrderedFactory
* @template PayloadType of HasPayloadInterface
*/
class CollectionOrderedFactory
这是因为用户无法指定
PayloadType
(甚至不能隐式指定)。
当您允许用户以一种或另一种方式设置
PayloadType
时,错误就会消失。例如,在下面的代码中,类通过构造函数参数接受类型信息:
<?php
/**
* @template PayloadType of PayloadInterface
* @implements HasPayloadInterface<PayloadType>
*/
class CollectionOrdered implements HasPayloadInterface
{
/**
* @param class-string<PayloadType> $payloadType
*/
public function __construct(private string $payloadType) {}
public function getPayload(): string
{
return $this->payloadType;
}
}
/**
* @template PayloadType of PayloadInterface
*/
class CollectionFactory
{
/**
* @param class-string<PayloadType> $payloadType
*/
public function __construct(private string $payloadType) {}
/**
* @return CollectionOrdered<PayloadType>
*/
public function makeCollection(): CollectionOrdered
{
return new CollectionOrdered($this->payloadType);
}
}
/**
* Class HasPayloadInterface
* @template PayloadType
*/
interface HasPayloadInterface
{
}
interface PayloadInterface
{
public function getPayload(): string;
}
class SimplePayload implements PayloadInterface
{
public function __construct(private string $payload) {}
public function getPayload(): string
{
return $this->payload;
}
}
我承认上面的代码相对无用,您可能需要另一种方式将类型信息传递到类中,但它解决了问题:
$ phpstan analyze --no-progress --no-ansi --level=9 -- test.php
[OK] No errors
以下是创建
CollectionOrdered<SimplePayload>
的方法:
$factory = new CollectionFactory(SimplePayload::class);
$collection = $factory->makeCollection();