Search code examples
phpphp-8

Convert type hinted php8 objects to json using json_encode


I have the following code.

class SomeObject implements JsonSerializable {
    public string $placeholder;
    public string $id;
    public string $model;
    public string $value;
    public bool $disabled;
    public bool $required;

    public function jsonSerialize()
    {
        return get_object_vars($this);
    }
}

class MainObject implements JsonSerializable
{
    public string $mainName;
    public SomeObject $someObject;

    public function __construct() {
        $this->mainName = (new ReflectionClass(MainObject::class))->getShortName();
        $this->someObject = new SomeObject();
    }

    public function jsonSerialize()
    {
        return get_object_vars($this);
    }
}

$main = new MainObject;
$jsonData = json_encode($main, JSON_PRETTY_PRINT);

>>> Result:
{
    "mainName": "MainObject",
    "someObject": []
}

I would like the MainObject to look like this

{
    "mainName": "MainObject",
    "someObject": {
        "placeholder": "",
        "id": "",
        "model": "",
        "value": "",
        "disabled": "",
        "required": ""
    }
}

however it seems that json_encode() method will only encode if objects have values assigned to them. if I make $someObject an associative array it works as expected.

How can I do this? Thanks in advance.


Solution

  • From the PHP manual of get_object_vars:

    Uninitialized properties are considered inaccessible, and thus will not be included in the array.

    So it's not possible to continue using get_object_vars in combination with the uninitialised class members. You'll either have to:

    • Initialise the variables, as proposed by Alex Howansky.

    • Use some additional trickery with get_class_vars(), which will return uninitialised variables. Using an array_merge to combine the two will result in an array with the desired keys.

      public function jsonSerialize()
      {
          return array_merge(
              get_class_vars(__CLASS__),
              get_object_vars($this)
          );
      }
      

      The values of the uninitialised variables will be null. If the empty strings as fallback are required, you can run the output through an array_map that applies the null coalescing operator:

      public function jsonSerialize()
      {
          return array_map(
              fn($value) => $value ?? '',
              array_merge(
                  get_class_vars(__CLASS__),
                  get_object_vars($this)
              )
          );
      }
      

    3v4l for reference.