phpstan - 返回通用的

问题描述 投票:0回答:1

我觉得问这么简单的问题很愚蠢,但我显然错过了一些基本的东西。

下面的 CollectionOrdered 类旨在“携带有效负载”,而 HasPayloadInterface 的目的是封装所有携带有效负载的类的操作,而不仅仅是 CollectionOrdered。

我有一个 CollectionOrderedFactory,它创建一个 CollectionOrdered 对象。我本以为工厂中 makeCollection 方法的返回类型将是 CollectionOrdered,正如我在下面所写的。

但是

Phpstan 返回“makeCollection() 应该返回 CollectionOrdered,但却返回 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();
    }
}

预先感谢您的一些指导。

php generics return-type phpstan
1个回答
0
投票

我可以在您的代码中看到两个问题:

  1. 这部分对我来说看起来是错误的,因为
    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
  1. 在以下代码中,无法将
    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();
© www.soinside.com 2019 - 2024. All rights reserved.