从抽象类强制类方法参数为常量

时间:2018-06-27 11:20:17

标签: php class oop enums

集成特性

trait Integration {
    public function executeRequest($url, $method, $data, $acceptType) {
        //Do Something
    }
}

接受类型抽象类

abstract class RestAcceptType {
    const xml= "text/xml";
    const html = "text/html";
    const json = "application/json";
    const text = "text/plain";
}

我试图从Rest Rest Type抽象类中找到一种方法,要求$acceptType方法参数为常量。

即:

$a = new Integration;
$a->executeRequest("http://example.com/endpoint", "POST", $dataArray, RestAcceptType::json);

可以,但是...

$a = new Integration;
$a->executeRequest("http://example.com/endpoint", "POST", $dataArray, "json");

应该失败并引发致命异常。理想情况下,它希望通过类型提示来做到这一点,但可以将其作为方法本身内部的一个单独的数据类型验证阶段来完成。

3 个答案:

答案 0 :(得分:1)

您可以使用类似php-enum的库。然后您可以输入提示枚举类型:

final class RestAcceptType extends Enum {
    public const XML = "text/xml";
    public const HTML = "text/html";
    public const JSON = "application/json";
    public const TEXT = "text/plain";
}

trait Integration {
    public function executeRequest($url, $method, $data, RestAcceptType $acceptType) {
        //Do Something
    }
}

$a = new class {
    use Integration;
};

$a->executeRequest("http://example.com/endpoint", "POST", $dataArray, RestAcceptType::JSON());

请注意,您不是在这里访问常量,而是调用返回单例的静态方法。

答案 1 :(得分:1)

您始终可以使用SplEnum,它与您将要获得的“标准”值非常接近。

class RestAcceptType extends SplEnum {

    const __default = self::xml;

    const xml= "text/xml";
    const html = "text/html";
    const json = "application/json";
    const text = "text/plain";
}

trait Integration {
  public function executeRequest($url, $method, $data, RestAcceptType $acceptType) {
    //Do Something
  }
}

$acceptType = new RestAcceptType(RestAcceptType::xml);

答案 2 :(得分:0)

不幸的是,不可能通过类型提示来做到这一点。 Type hints can only operate at the level of class, interface or scalar-type level

很常见,此模式是通过为您的类提供“已知”常量列表来实现的,然后您可以通过同一类上的方法进行检查,也可以通过简单的in_array检查列表是否公开。因此,您可以将以下内容添加到RestAcceptType类中:

public static function isValidAcceptType($type)
{
    return in_array($type, [
        self::xml,
        self::html,
        self::json,
        self::text,
    ]);
}

然后,您可以在executeRequest方法的顶部使用此命令,例如:

if (!RestAcceptType::isValidAcceptType($acceptType)) {
  throw new InvalidArgumentException;
}

我知道这不是最干净的模式(特别是因为它意味着在添加新常量时进行两次更改),但是由于缺少使用ReflectionClass::getConstants之类的东西,因此不可能在类的常数。至少在我看来,这也不是特别干净(尽管这正是其他答案中的库的工作方式,因此绝对是一种选择)。