21

I am wondering why it is not possible to provide an __toString implementation for enum.

IDE says "Enum may not include '__toString'". However it was the first thing I thought about once I created enum. Previously I used Value Objects encapsulating strings in my code, which utilized string casting when necessary. Now I would like to migrate 'em into enums, but those resist.

#[Immutable]
enum SaveKlinesFromApiQueue: string
{
    case DEFAULT = 'save_klines_from_api_queue';
    case PRIORITY = 'save_klines_from_api_priority_queue';

    public function __toString(): string
    {
        return $this->value;
    }
}
rela589n
  • 817
  • 1
  • 9
  • 19
  • does $this->value has something in it or it's empty? – benzo Dec 05 '21 at 15:42
  • 8
    The RFC for enums explicitly [disallowed pretty much all magic methods](https://wiki.php.net/rfc/enumerations#magic_read-methods), the stated concern of it was around state and/or dynamic-ness. I think the overall idea is that you are either working with strings, or you are working with something at a higher level, and `__toString()` would present the opportunity for people (while debugging) to be confused because it would allow the Enum to be passed to methods that accept string-typed arguments, just like classes. – Chris Haas Dec 05 '21 at 16:31
  • Each case is an object instance of `SaveKlinesFromApiQueue`. When you do `echo SaveKlinesFromApiQueue;` what should `$this` refer to ? – Rain Dec 07 '21 at 02:37
  • 1
    @ChrisHaas > to be confused because it would allow the Enum to be passed to methods that accept string-typed arguments Not if they use strict types, and if they don't they deserve to be confused. > the stated concern of it was around state and/or dynamic-ness By definition an Enum must not have any state All objects in PHP can have a __toString method, this pretty usefull when displaying grids for example, with enums we have to go back to type checking, this can't be a good idea. – vitoriodachef Mar 13 '22 at 07:09
  • 1
    @vitoriodachef, strict types is optional and [debatable](https://github.com/symfony/symfony/issues/28423) , “deserve” is an opinion, and a harsh one IMHO. Regardless, I’m not involved in the RFC process, just a commenter on it here. The longer discussion on the RFC is [here](https://externals.io/message/112626). Also, the RFC has a dedicated section on “Auto-scalar conversion” that might be of interest. If you believe this to be an important enough feature, contact the list or the RFC authors and state your case. – Chris Haas Mar 13 '22 at 14:49
  • Have anyone seen rfc about implicit implementation of Stringable interface for backed enums? – rela589n Jul 16 '22 at 10:40

3 Answers3

8

I think you shouldn't use Enum if you want to use it like const in a regular class. Consider creating an abstract class instead like this:

abstract class SaveKlinesFromApiQueue
{
    public const DEFAULT = 'save_klines_from_api_queue';
    public const PRIORITY = 'save_klines_from_api_priority_queue';
}

Aside from the correct use of Enum, in your case you can use:

echo SaveKlinesFromApiQueue::DEFAULT->name;

Result: "DEFAULT"

or

echo SaveKlinesFromApiQueue::DEFAULT->value;

Result: "save_klines_from_api_queue"

Scissorro
  • 139
  • 1
  • 2
2

As chris mentions, magic methods are not allowed.

For the 2 most(?) common usecases:

To get the string value of a single one, you can just use ->value.

If you want the string values of all of them, just add a loop in a method:

    public static function strings(): array
    {
        $strings = [];
        foreach(self::cases() as $case) {
            $strings[] = $case->value;
        }
        return $strings;
    }
Puggan Se
  • 5,738
  • 2
  • 22
  • 48
  • 3
    That is not the case. When project has [value objects](https://martinfowler.com/bliki/ValueObject.html) which behave like enums, and such objects define magic methods - you (well, me) are out of luck. Somewhere in project may not be strict types enabled and some method arguments are type-hinted with string (it was done when there were no value objects). Value objects implemented __toString method and it worked fine. Now, when enums exist, I would like to convert such value objects into enums, however apparently I can't do it without troubles. – rela589n Feb 09 '22 at 19:28
-2

Implementing JsonSerializable works if your use-case involves converting an enum property to json.

enum ParameterTypeEnum implements \JsonSerializable
{
    case QUERY;
    case COOKIE;
    case HEADER;
    case PATH;

    public function getType(): string
    {
        return match($this) {
            ParameterTypeEnum::QUERY => 'query',
            ParameterTypeEnum::COOKIE => 'cookie',
            ParameterTypeEnum::HEADER => 'header',
            ParameterTypeEnum::PATH => 'path',
        };
    }

    public function jsonSerialize(): mixed
    {
        return $this->getType();
    }
}
cnizzardini
  • 1,196
  • 1
  • 13
  • 29