yiisoft / json

JSON encoding and decoding
https://www.yiiframework.com/
BSD 3-Clause "New" or "Revised" License
26 stars 8 forks source link

Can process ArrayableInterface with Json::encode(), like Yii2 ? #45

Closed niqingyang closed 8 months ago

niqingyang commented 8 months ago

What steps will reproduce the problem?

Json::encode() did not handle the object of ArrayableInterface, like Yii2

/**
 *
 * @property int $id
 * @property string|null $name
 * @property string|null $phone
 */
class User implements ArrayableInterface
{
    use ArrayableTrait;

   public ?int $id = null;

   public ?string $name = null;

   public ?string $phone = null;

    public function toArray(array $fields = [], array $expand = [], bool $recursive = true): array
    {
        return [
           'demo' => 'demo'
        ];
    }
}

$user = new User();
$user->id = 1;
$user->name = 'xxx';
$user->phone = 'xxx';

$data = Json::decode(Json::encode($user));

echo $data['demo'];

What is the expected result?

'demo'

What do you get instead?

null

Additional info

Q A
Version 1.0.?
PHP version 8.1
Operating system Windows 10
Tigrov commented 8 months ago

Json::encode() supports JsonSerializable interface. Needs to add JsonSerializable to the class interfaces.

class User implements ArrayableInterface, JsonSerializable
{
...
    public function jsonSerialize(): mixed
    {
        return $this->toArray();
    }
...
}
niqingyang commented 8 months ago

Json::encode() supports JsonSerializable interface. Needs to add JsonSerializable to the class interfaces.

class User implements ArrayableInterface, JsonSerializable
{
...
    public function jsonSerialize(): mixed
    {
        return $this->toArray();
    }
...
}

ok

vjik commented 8 months ago

Also we can add support ArrayableInterface (yiisoft/arrays will be optional dependency):

if ($data instanceof ArrayableInterface) {
    return self::processArray($data->toArray());
}

Does that make sense? Are there any cases when object with ArrayableInterface should be serialized to json in different way?

Tigrov commented 8 months ago

Does that make sense? Are there any cases when object with ArrayableInterface should be serialized to json in different way?

I'm for explicit conversion to json using JsonSerializable::jsonSerialize().

For example, ActiveRecord objects will be converted using ActiveRecord::getAttributes(), but if to support ArrayableInterface inside Json::encode() the result will be different.

class Model extends ActiveRecord
{
    ...
    public function fields(): array
    {
        return [
            'firstName' => 'first_name',
            'lastName' => 'last_name',
        ];
    }
}

Result for current implementation

$json = Json::encode($model);
// {"first_name":"John","last_name":"Smith"}

Result if to support ArrayableInterface

$json = Json::encode($model);
// {"firstName":"John","lastName":"Smith"}