Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can PHP 8 Enum be passed as function argument?

Tags:

php

I have a Enum that implements a given interface:

namespace App\Model;

use Symfony\Contracts\Translation\TranslatableInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

enum UserRole: string implements TranslatableInterface
{
    case User = 'ROLE_USER';
    case ZoneManager = 'ROLE_ZONE_MANAGER';
    case SuperAdmin = 'ROLE_SUPER_ADMIN';

    public function trans(TranslatorInterface $translator, ?string $locale = null): string
    {
        return match ($this) {
            self::User => $translator->trans('roles.user', locale: $locale),
            self::ZoneManager => $translator->trans('roles.zone_manager', locale: $locale),
            self::SuperAdmin => $translator->trans('roles.super_admin', locale: $locale),
        };
    }
}

I wrote a function to return an array of enum value (as string) and the corresponding translation:

private function translateEnum(\BackedEnum&TranslatableInterface $enum)
{
    return array_combine(
        array_map(fn(\BackedEnum $v) => $v->value, $enum::cases()),
        array_map(
            fn(\BackedEnum&TranslatableInterface $v) => $v->trans($this->translator), 
            $enum::cases()),
    );
}

How can I pass UserRole enum to my function, an a "whole"? Of course UserRole::class won't work (is a string) neither UserRole alone works.

like image 954
gremo Avatar asked Sep 28 '26 06:09

gremo


1 Answers

If you don't mind using static analysis, both Psalm and PHPStan support the class-string<T> type annotation.

Define your function as follows:

/**
 * @param class-string<BackedEnum&TranslatableInterface> $enumClass
 */
private function translateEnum(string $enumClass)
{
    return array_combine(
        array_map(fn(\BackedEnum $v) => $v->value, $enum::cases()),
        array_map(
            fn(TranslatableInterface $v) => $v->trans($this->translator), 
            $enumClass::cases()),
    );
}

Both Psalm and PHPStan will now complain if you pass a class string that does not implement BackedEnum&TranslatableInterface.

interface TranslatableInterface {}

enum MyBackedEnum: string implements TranslatableInterface {}

enum NotABackedEnum {}

enum NotATranslatableEnum: string {}

translateEnum(MyBackedEnum::class); // Ok

translateEnum(NotABackedEnum::class); // Error

translateEnum(NotATranslatableEnum::class); // Also an error

See here for a playground example: https://phpstan.org/r/9e56fbe5-e8c7-4300-a32c-aad79976f47c.

like image 143
Pieter van den Ham Avatar answered Sep 29 '26 19:09

Pieter van den Ham



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!