-
Type: New Feature
-
Resolution: Fixed
-
Priority: Unknown
-
Affects Version/s: None
-
Component/s: None
-
None
Proposed Behavior
Prohibit encoding of pure enums.
Encode BackedEnum instances as their backing value.
Ignore enums indicated in a “__pclass” field during BSON encoding (see PHPC-2159). While enums were previously never instantiatable from decoding BSON, a previous driver version might have been used to encode a Persistable enum to BSON. That is not a use case we want to support, but it would be inconsistent to raise an exception in this case.
Prohibit enums from implementing Persistable and Unserializable using the “interface_gets_implemented” object handler. We will remove previously introduced code in 1.15-dev that instantiated enums from case strings, and will not add behavior to instantiate BackedEnums from case values. Additionally, the bsonUnserialize() method was never relevant for enums, since they have no state.
Allow pure and backed enums to implement Serializable. Since enums are objects, they are permitted to implement Serializeable and that implementation will take precedence over standard BSON encoding rules (as it does with BSON type classes). Two thoughts on this:
- The previous behavior (i.e. encoding as a BSON document with a “name” and optional “value” fields) can be achieved by implementing Serializable and returning “(array) $this” from bsonSerialize().
- I certainly don’t want to encourage Serializable implementations for enums, but I also don't see a reason we need to prohibit it. It could technically provide a back door for users to round-trip non-backed enums. For example, the bsonUnserialize() method of an Unserializable class containing an enum could convert the pure/backed enum’s bsonSerialize() document representation back into an enum.
The original issue description is below.
As reported in mongodb/mongo-php-driver#1315, an enum class implementing MongoDB\BSON\Persistable cannot be instantiated during BSON unserialization:
#!/usr/bin/php <?php declare(strict_types=1); use MongoDB\BSON\Persistable; use MongoDB\Client; require_once __DIR__ . '/vendor/autoload.php'; enum Test : string implements Persistable { case FOO = 'F'; case BAR = 'B'; public function bsonSerialize() { return (array)$this; } public function bsonUnserialize(array $data) { } } $client = new Client(driverOptions: ['typeMap' => ['array' => 'array']]); $database = $client->selectDatabase('test'); $collection = $database->selectCollection('test'); $collection->insertMany([Test::FOO, Test::BAR]); var_dump($collection->find()->toArray());
This results in the following error:
PHP Warning: Uncaught Error: Cannot instantiate enum Test in /project/test.php:26 Stack trace: #0 [internal function]: MongoDB\Driver\Cursor->rewind() #1 /project/test.php(26): MongoDB\Driver\Cursor->toArray() #2 {main} thrown in /project/test.php on line 26 PHP Stack trace: PHP 1. {main}() /project/test.php:0 PHP 2. MongoDB\Driver\Cursor->toArray() /project/test.php:26 PHP 3. MongoDB\Driver\Cursor->rewind() /project/test.php:26 PHP Fatal error: Couldn't find implementation for function bsonUnserialize in Unknown on line 0 PHP Stack trace: PHP 1. {main}() /project/test.php:0 PHP 2. MongoDB\Driver\Cursor->toArray() /project/test.php:26 PHP 3. MongoDB\Driver\Cursor->rewind() /project/test.php:26
- related to
-
PHPC-2170 Create enums for eligible types
- Backlog
-
PHPC-2159 Consider enums and traits in BSON decoding instantiatable checks
- Closed
-
PHPLIB-1040 Create tutorial demonstrating BSON handling of enum types
- Closed
- links to