三元表达式中的 enum class

enum class in ternary expression

最近 PHP 引入了枚举。我正在 laravel 项目中试用它们。我的枚举 class 在这里:

namespace App\Enums;

enum AlertType
{
    case SUCCESS;
    case ERROR;
}

我正在尝试创建一个警报 class,它将在构造函数中使用枚举来设置警报的严重性,这将决定向用户呈现什么颜色。这是 class:

<?php

namespace App\View\Components;

use App\Enums\AlertType;
use Illuminate\View\Component;

class Alert extends Component
{
    public string $contextClass;

    public function __construct(public string $message, AlertType $alertType = AlertType::SUCCESS)
    {
        $this->setContextClassFromAlertType($alertType);
    }

    public function setContextClassFromAlertType(AlertType $alertType)
    {
        $this->contextClass = ($alertType === AlertType::SUCCESS ? 'success' : 'error');
    }

    public function getClassListFromType()
    {
        return [
            'border-' . $this->contextClass,
            'text-' . $this->contextClass
        ];
    }

    public function render()
    {
        return view('components.alert', [
            'class' => implode(' ', $this->getClassListFromType())
        ]);
    }
}

此警报将用于使用 Laravel Livewire 和 blade 组件构建的登录表单:

<form class="grid grid-cols-min-auto-1 gap-x-2" id="login" action="/login" method="post">
    <x-alert :message="$errorMessage"/>
    @csrf
    <label for="email" class="mb-2 text-lg text-sans w-min mt-2 font-thin">Email</label>
    <x-basic-input wire:model="email" placeholder="{{ $emailPlaceholder }}"/>
    <label for="password" class="mb-2 text-lg text-sans w-min mt-2 font-thin">Password</label>
    <x-basic-input wire:model="password"/>
</form>

当我显示登录表单时出现以下错误:

Cannot instantiate enum App\Enums\AlertType (View: /resources/views/livewire/forms/login.blade.php)

我认为我在 Alert 组件中使用 enum 有问题,但我不确定在哪里。谁能指出我正确的方向。我查看了枚举的 rfc,但我看不到任何明显的错误

我能够重现这个错误;在我的例子中,堆栈跟踪返回到 barryvdh/laravel-debugbar 包,不确定这对你来说是否相同。我能够通过将枚举更改为 backed enum.

来解决它

无论如何我都建议进行此更改,因为我预计在很多情况下字符串比枚举实例更易于使用。 (尽管说实话,这看起来像是尝试使用一项新功能,只是因为它在那里,而不是因为它有意义。)

namespace App\Enums;

enum AlertType: string
{
    case SUCCESS = 'success';
    case ERROR = 'error';
    case INFO = 'info';
}

在支持的枚举中,每个项目都有一个字符串表示,可以使用 value 属性 访问,我们在构造函数中这样做:

<?php

namespace App\View\Components;

use App\Enums\AlertType;
use Illuminate\View\Component;

class Alert extends Component
{
    public string $contextClass;

    public function __construct(
        public string $message,
        AlertType $alertType = AlertType::SUCCESS,
    )
    {
        $this->contextClass = $alertType->value;
    }

    public function getClassListFromType()
    {
        return [
            'border-' . $this->contextClass,
            'text-' . $this->contextClass
        ];
    }

    public function render()
    {
        return view('components.alert', [
            'class' => implode(' ', $this->getClassListFromType())
        ]);
    }
}

您现在可以使用 from()tryFrom() 方法,这些方法可以增加保存在变量中的警报类型的灵活性。例如:

<x-alert :message="$errorMessage" :type="App\Enums\AlertType::from($errorType)"/>

我认为这里的问题是由于依赖注入。在构造函数中,我输入了一个枚举,所以 Laravel 容器试图创建一个 class 的实例来传递,但它不起作用,因为枚举是可实例化的。

如果我更新容器以像这样手动解析类型提示实例:

$this->app->bind(Alert::class, function ($app) {
    return new Alert('this is a message', AlertType::SUCCESS);
});

然后问题就解决了,一切正常。我需要更改我在这里使用枚举的方式,因为 @miken32 建议使用支持的枚举并改为依赖字符串。否则我需要为我想传递枚举的每个方法重写容器注入。