首页 > 解决方案 > PHP - 将字符串值分配给类型提示为枚举的变量

问题描述

我有一些应用程序的 PHP 片段,我试图限制来自 JavaScript 应用程序前端请求的输入。该页面使用 JSON 对象发送请求,该对象包含我指定为“打开”、“完成”或“关闭”的字段值。我想防止不需要的输入篡改或值被发送。

问题:

下面的属性 $eventstatus 是用枚举提示的类型,但是当我在$array['EventStatus']PHP (7.4.9) 中分配字符串值时,会报告我的类型不兼容的错误。事实上,当我为它分配一个字符串时,它需要看到一个状态类型。
我该如何解决?

$event->eventstatus = $array['EventStatus'];   

枚举类(状态)

<?php
    namespace app\enums;

    abstract class Status
    {
        const Open = 'Open';
        const Complete = 'Complete';
        const Closed = 'Closed';
    }

映射器类成员函数-片段,下面的代码采用数组值并将其映射到类属性

<?php
    function mapFromArray($event, $array) {
        if (!is_null($array['EventStatus'])) $event->eventstatus = $array['EventStatus'];   
    }

模型类

<?php
    namespace data\model;
    use app\enums\Status;

    class Event
    {
        public $eventid;  
        public $riskid;        
        public $eventtitle;
        public Status $eventstatus;
    }

标签: php

解决方案


您的类型提示实际上告诉PHP您希望$eventstatus成为. 但这些值实际上只是简单的字符串:,和. 所以正确的类型提示是:Status'Open''Complete''Closed'

<?php
    namespace data\model;
    use app\enums\Status;

    class Event
    {
        // ...
        public string $eventstatus;
    }

但是有了这个 PHP 接受任何 string,而不仅仅是一个“有效”的。在这里使用正确的 Enums 会有所帮助,但目前 PHP 7 没有对 Enums 的原生支持(尽管它是为 PHP 8.1 实现的)。

如果您想使用Status该类以获得更易读的代码,您只需将类型提示更改为string.

如果要验证输入数据,可以像这样扩展代码:

<?php
    namespace app\enums;

    abstract class Status
    {
        const Open = 'Open';
        const Complete = 'Complete';
        const Closed = 'Closed';
        const Valid_Statuses = [
                self::Open,
                self::Complete,
                self::Closed,
        ];
    }
function mapFromArray($event, $array) {
    if (!is_null($array['EventStatus'])) {
        if (in_array($array['EventStatus'], Status::Valid_Statuses)) {
            $event->eventstatus = $array['EventStatus'];
        } else {
            // handle invalid status value here
        }
    }
}

如果您想使用严格的类型提示来确保任何地方的有效性,您需要将值包装到类的实例中,例如:

namespace app\enums;

abstract class Status
{
    const Open = 'Open';
    const Complete = 'Complete';
    const Closed = 'Closed';
    const Valid_Statuses = [
        self::Open,
        self::Complete,
        self::Closed,
    ];

    private string $value;

    public function __construct(string $value) {
        if (!in_array($value, self::Valid_Statuses)) {
            throw \InvalidArgumentException(sprintf('Invalid status "%s"', $value));
        }

        $this->value = $value;
    }

    public function getValue(): string {
        return $this->value;
    }

    public function __toString(): string {
        return $this->value;
    }
}
function mapFromArray($event, $array) {
    if (!is_null($array['EventStatus'])) {
        try {
            $event->eventstatus = new Status($array['EventStatus']);
        } catch (\Exception $exception) {
            // handle invalid status value here
        }
    }
}

推荐阅读