首页 > 解决方案 > Php doc:键入一个字符串类名,该类名将始终实现给定的接口

问题描述

我有一个返回类名(字符串)的函数,但返回的类总是实现相同的接口:

<?php

interface BaseInterface {}
class SomeClass implements BaseInterface {}
class AnotherClass implements BaseInterface {}

/**
 * @return ....
 */
function getClassName($someCondition): string
{
    if ($someCondition === 42) {
        return SomeClass::class;
    } else {
        return AnotherClass::class;
    }
}

是否可以在@return标签中提供此信息?像这样的东西(想象的语法):

/** @return BaseInterface::class */

最终目标是让 IDE 理解这getClassName(...)::myInterfaceMethod()是有效的。

编辑:问题的具体用例

这是一个可运行的示例,显示了我::class在实际代码中的使用方式。

我将代码改写得尽可能短,但它实际上是 Symfony 项目的一部分,使用 php 7.4 运行。

这个想法是为每个社交网络实现一个类;所有这些小类都实现SocialNetworkInterface并且只有静态方法。它们永远不会被实例化,但是通过调用它们的静态方法来查询它们。

注意:变量$user应该输入为User,但为了缩短代码,我只是在参数中不输入它们。

我的问题中解释的问题(IDE 抱怨)发生在第 79 行,里面renderLinkForUserNetwork()

$class = $networkClass::getFontAwesomeLogoClass();
$url = $networkClass::getUrlForUsername($networkUsername);
<?php

interface SocialNetworkInterface
{
    public static function getName(): string;
    public static function getBaseUrl(): string;
    public static function getUrlForUsername(string $username): string;
    public static function getFontAwesomeLogoClass(): string;
}

abstract class AbstractSocialNetwork implements SocialNetworkInterface
{
    public static function getUrlForUsername(string $username): string
    {
        // Most social networks use this kind of urls, but of course, this can
        // be overloaded in final classes:
        $baseUrl = static::getBaseUrl();
        return "$baseUrl/$username";
    }

    public static function getFontAwesomeLogoClass(): string
    {
        $name = static::getName();
        return "fab fa-$name";
    }
}

class Facebook extends AbstractSocialNetwork
{
    public static function getName(): string
    {
        return 'facebook';
    }

    public static function getBaseUrl(): string
    {
        return ('https://www.facebook.com');
    }
}

class Twitter extends AbstractSocialNetwork
{
    public static function getName(): string
    {
        return 'twitter';
    }

    public static function getBaseUrl(): string
    {
        return ('https://twitter.com');
    }
}

class SocialNetworkHandler
{
    public function getSocialNetworksForUser($user): array {
        // Should return all the social network classes for which the user has
        // information to give (normally depends on the user, fake data is given
        // here for simplicity):
        return [
            Facebook::class,
            Twitter::class,
        ];
    }

    public function renderLinkForUserNetwork($user, string $networkClass): ?string
    {
        // Make it runnable for this example, normally retrieved from $user
        // and $networkClass:
        $networkUsername = 'example';

        // An ugly workaround: of course, $networkClass is not an instance of
        // SocialNetworkInterface, but calling static methods work the same
        // between class name strings and objects:
        /** @var SocialNetworkInterface $networkClass */

        // When not using the ugly workaround just above, the IDE is complaining
        // here (method not found in string):
        $class = $networkClass::getFontAwesomeLogoClass();
        $url = $networkClass::getUrlForUsername($networkUsername);

        return <<< HTML
            <a href="$url"><i class="$class"></i></a>
        HTML;
    }

    public function renderLinksForUser($user): string
    {
        $links = [];
        foreach ($this->getSocialNetworksForUser($user) as $networkClass) {
            $links[] = $this->renderLinkForUserNetwork($user, $networkClass);
        }
        return implode("\n", $links);
    }
}

$handler = new SocialNetworkHandler();
$user = null; // Should be a User entity
echo $handler->renderLinksForUser($user);

输出:

    <a href="https://www.facebook.com/example"><i class="fab fa-facebook"></i></a>
    <a href="https://twitter.com/example"><i class="fab fa-twitter"></i></a>

标签: phpphpdoc

解决方案


不,不幸的是,它不是这样工作的。您应该在此处指定返回类型,即使 BaseInterface::class 是动态的,它也会是返回(类型为string)。


推荐阅读