Uploaded image for project: 'PHP Driver: Extension'
  1. PHP Driver: Extension
  2. PHPC-2083

BSON handling for enum classes

    • Type: Icon: New Feature New Feature
    • Resolution: Fixed
    • Priority: Icon: Unknown Unknown
    • 1.15.0
    • Affects Version/s: None
    • Component/s: None
    • Labels:
      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
      

            Assignee:
            jmikola@mongodb.com Jeremy Mikola
            Reporter:
            jmikola@mongodb.com Jeremy Mikola
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: