eloquent / enumeration

An enumeration implementation for PHP.
MIT License
147 stars 8 forks source link

serializable #23

Open ukhvan opened 7 years ago

ukhvan commented 7 years ago

What is the correct way to use your library in serializable object? Especially, Multiton class. Is it possible? The constructor is protected, thus, there are some difficulties…

ezzatron commented 7 years ago

Here's an example of how it can be done, using the Planet multiton from the README:

class SerializableObject implements Serializable
{
    public function __construct(Planet $planet)
    {
        $this->planet = $planet;
    }

    public function serialize()
    {
        return serialize(['planet' => $this->planet->key()]);
    }

    public function unserialize($serialized)
    {
        $data = unserialize($serialized);
        $this->planet = Planet::memberByKey($data['planet']);
    }
}

$object = new SerializableObject(Planet::EARTH());
$serialized = serialize($object);
$unserialized = unserialize($serialized);

var_dump($object->planet === $unserialized->planet); // outputs bool(true)
ukhvan commented 7 years ago

Thank you for your answer! It's a pity that it's impossible to make the Planet class itself serializable, and instead, one has to care about its serialization in all client classes which use it. Thank you for the example you've provided though.

ezzatron commented 7 years ago

No worries. To explain why this is the only option:

PHP only allows you to modify the properties of the object being unserialized, it's impossible to change which instance is returned. Unserializing a particular multiton member twice would produce two separate instances, which breaks the core functionality of this library.

AbstractMultiton should probably implement Serializable and throw an exception to prevent unexpected problems arising from this issue.

ukhvan commented 7 years ago

Unserializing a particular multiton member twice would produce two separate instances, which breaks the core functionality of this library.

Thus, the only option to make serializable enumeration is to make it non-multitons, but regular objects, and compare them not via strict comparison operator ===, but via calling Java-style equals method like this: $planet->equals(Planet::Earth()) — which will not break the core functionality of this library, but will change the strategy of comparison of enumeration instances.

Again, thank you for your answer, it clarified my view on this problem.

AbstractMultiton should probably implement Serializable and throw an exception

Completely agree with you in this.

ezzatron commented 7 years ago

You're welcome. On a side note, the README does mention strict equality:

For each member of the enumeration, a single instance of the enumeration class is instantiated (that is, an instance of HttpRequestMethod in the above example). This means that strict comparison (===) can be used to determine which member has been passed to a function:

function handleHttpRequest(HttpRequestMethod $method, $url, $body = null)
{
    if ($method === HttpRequestMethod::POST()) {
        // handle POST requests...
    } else {
        // handle other requests...
    }
}