PHP 8.1 enum const expressions problem

  115607
July 29, 2021 22:16 nesk@xakep.ru (=?UTF-8?B?0JrQuNGA0LjQu9C7INCd0LXRgdC80LXRj9C90L7Qsg==?=)
Hello internals! I apologize if such a discussion has already taken place, but I didn't find anything like it.
 
When working with enums, I ran into problems that are currently not resolved. In some cases, enumerations require self references and constant arithmetic expressions:
 
enum Example: int
{
    case A = 0b0001;
    case B = 0b0010;
    case C = 0b0100;
 
    public const EXAMPLE_MASK = self::A | self::B; // << Invalid expression
    public const EXAMPLE_MASK2 = self::A->value | self::B->value; // << Same
}
 
Similar examples can be taken in the existing PHP code, for example, for attributes (Attribute::TARGET_ALL) which is a binary mask for existing «targets». Thus, if targets for attributes were implemented through enumerations, and not through constants, then it would be impossible to implement such functionality.
 
In addition, enumeration values are not part of constant expressions, so implementation through "Example::A->value" is also not available.
 
Can you please tell me, maybe there have already been some discussions of this problem? And if not, then maybe we should solve this problem before PHP 8.1 release? Since it seems to me that the lack of such functionality is quite critical.
 
--
Kirill Nesmeyanov
 
  115608
July 29, 2021 23:23 larry@garfieldtech.com ("Larry Garfield")
On Thu, Jul 29, 2021, at 5:16 PM, Кирилл Несмеянов wrote:
> > Hello internals! I apologize if such a discussion has already taken > place, but I didn't find anything like it. >   > When working with enums, I ran into problems that are currently not > resolved. In some cases, enumerations require self references and > constant arithmetic expressions: >   > enum Example: int > { >     case A = 0b0001; >     case B = 0b0010; >     case C = 0b0100; >   >     public const EXAMPLE_MASK = self::A | self::B; // << Invalid expression >     public const EXAMPLE_MASK2 = self::A->value | self::B->value; // << Same > } >   > Similar examples can be taken in the existing PHP code, for example, > for attributes (Attribute::TARGET_ALL) which is a binary mask for > existing «targets». Thus, if targets for attributes were implemented > through enumerations, and not through constants, then it would be > impossible to implement such functionality. >   > In addition, enumeration values are not part of constant expressions, > so implementation through "Example::A->value" is also not available. >   > Can you please tell me, maybe there have already been some discussions > of this problem? And if not, then maybe we should solve this problem > before PHP 8.1 release? Since it seems to me that the lack of such > functionality is quite critical.
What you're describing is enum sets. That is, a value that is itself a union of two enum values. Those are not supported at this time. It's actually a bit tricky to do, since internally enum cases are not a bit value but an actual full PHP object. So self::A | self::B would be trying to bitwise-OR two objects, which is of course meaningless. The second doesn't work because technically self::A is an object, not a constant, so it cannot be used in a constant expression. The only dynamicness added in 8.1 was for "new" expressions in initializers. The objects don't exist at compile time so they cannot be reduced down to a constant value pre-runtime. I agree the current situation is suboptimal. I don't think anyone is opposed to enum sets, but they're a non-trivial amount of work to do and we haven't figured out how to do them yet. There's no simple way to address it as as bug, so any larger effort will have to wait for 8.2. --Larry Garfield