php-enum
php-enum copied to clipboard
Enum instances aren't singletons
Ideally, SomeEnum::Foo() should always return the same instance of SomeEnum, so you can do $someEnumValue1 === SomeEnum::Foo() instead of $someEnumValue1->getValue() !== SomeEnum::Foo
Yes that's really something I'd like to have!
Maybe a 2.0 version could make the constructor private? Currently there is a "cache" so that MyEnum::FOO() always returns the same object, the only problem is that users can still do new MyEnum(MyEnum::FOO)…
But then what about deserialized enums…
Oh, deserialisation would be an issue :/
Also, I discovered that I may just be able to use == as it does structural comparison.
yep forgot to mention that, I use == too.
See #43 or adrium/php-enum version 1.5.1
What would be the point of singletons? Enums are value objects and value objects equality is not based on identity:
a value object is a small object that represents a simple entity whose equality is not based on identity
The current implementation of Enum is correct because it contains an equals() method that tests equality based on type and value.
@shadowhand that's a good point indeed. I think the main "issues" would be practicality (ability to use ===) and performances.
But this package has worked fine until now without singletons, a 2.0 would create a lot of conflicts downstream for very little gain so I think it's acceptable to keep this on hold unless we find a very good reason to release a v2.0.
Constructor is public, so it will automatically create new instance.
To use singletons, you can use search method, like this:
$singletone = MyEnum::{MyEnum::search($value)}();
Not best practice, but it will always create single instance
@KartaviK see my response above. Enums (as implemented in this package) are value objects, and value objects have equality by state, not by being singletons.
Creating a new object for each enum usage is memory wasting. Imagine you are fetching a huge amount of rows from the database. High memory usage affects performance in general (e.g. GC).
Comparing the other languages implementations you can see that they use the singletons:
- Python https://repl.it/@torinaki/Python-Enum-is-Singleton
- Java https://repl.it/@torinaki/Java-Enum-is-Singleton
What would be the point of singletons? Enums are value objects and value objects equality is not based on identity:
a value object is a small object that represents a simple entity whose equality is not based on identity
The current implementation of Enum is correct because it contains an
equals()method that tests equality based on type and value.
IMO, the way this library instantiates its enum values is a detail of implementation. If you disagree, then this library should clearly state in its description that it relies on the value object definition of object equality.
I support @githoober. IMO it leads to misunderstanding. Enums and ValueObjects behave differently. Enums (as I showed in a comment above) in most languages represents the set of constants. In turn, ValueObject is a structure that can be instantiated (!) with any set of values for defined parameters.
I came to a conclusion, that It'll require several BC breaks and would be problematic to implement in this library in the near future.
As a result, I have created my own implementation of Enums: https://github.com/dbalabka/php-enumeration
The implementation is based on Enumeration Classes and is very close to Java Enums and Python Enums. In the end, I realize that Enumeration Classes address a bunch of other open issues sitting in the backlog:
- #8 - all enums are singletons. Also, I have provided the workaround for serialization issue
- #99 - the autocompletion isn't a problem anymore due to the static properties has been employed instead of magic methods.
- #65, #53 - developer can customize the Enum element instantiation and provide any type and count of parameters into the constructor (e.g. arrays, duplicated values)
- #7 - the value can be omitted to create simple named Enum
Please, don't do it (i.e. put enums into singletons). Enums are a value objects, and this is bad idea to have singletons for value object. In normal languages to compare value objects you have to implement ->equals() method on it to make comparisons (thanks, current Enum class already have it).
@fruit thank you for your opinion. As I showed in a comment above, Java and Python use an exactly single object instance to represent Enum value.
There is also a great answer on StackOverflow that explains how ->equals() works in Java and what relation Enum has to a singleton.
Please correct me if I'm mistaken somewhere.
I think it would help to mention in README.md that strict comparison won't work as expected (b/c it is not mentioned that php-enum is not singleton) and that there are 2 workarounds:
- weak comparison i.e.
== - method
->equals()
@alexkuc sure that makes sense, feel free to send a PR.