maaaarcel/devalue-php

一个用于字符串化和解析复杂数据的库。灵感来源于devalue JavaScript库。

1.0.2 2023-02-11 23:49 UTC

This package is auto-updated.

Last update: 2024-09-12 03:08:15 UTC


README

这是由devalue(一个用于字符串化和解析过于复杂的JSON数据的JavaScript库)的PHP端口。请查看原始仓库以了解所有功能。

解析和字符串化逻辑的所有荣誉归功于devalue库的创建者和贡献者。这个实现中的逻辑基本上是相同的,但为了提高PHP的性能做了一些轻微的修改。

安装

使用composer安装

composer require maaaarcel/devalue-php

用法

Devalue类具有stringifyparseunflatten方法,用于后端进行字符串化和解析。

use Maaaarcel\DevaluePhp\Devalue;
use Maaaarcel\DevaluePhp\JavaScript\JsBigInt;
use Maaaarcel\DevaluePhp\JavaScript\JsNumberObject;
use Maaaarcel\DevaluePhp\JavaScript\JsRegExp;
use DateTime;

$obj = new stdClass();
$obj->self = $obj;
$data = [
    'recursiveObject' => $obj,
    'regex' => new JsRegExp('.+', 'g'),
    'date' => new DateTime('2023-01-16'),
    'autoConverted' => INF,
    'undefined' => JsValue::Undefined,
    'normalNumber' => 1,
    'array' => [new JsBigInt(1), new JsNumberObject(2)]
];
$dataStr = Devalue::stringify($data);
// => '[{"recursiveObject":1,"regex":2,"date":3,"autoConverted":-4,"undefined":-1,"normalNumber":4,"array":5},{"self":1},["RegExp",".+","g"],["Date","2023-01-16T00:00:00.000Z"],1,[6,7],["BigInt","1"],["Object",2]]'

$parsedData = Devalue::parse($dataStr);
// => object(stdClass)#507 (7) {
//   ["recursiveObject"]=>
//   object(stdClass)#505 (1) {
//     ["self"]=>
//     *RECURSION*
//   }
//   ["regex"]=>
//   object(Maaaarcel\DevaluePhp\JavaScript\JsRegExp)#506 (2) {
//     ["source":"Maaaarcel\DevaluePhp\JavaScript\JsRegExp":private]=>
//     string(2) ".+"
//     ["flags":"Maaaarcel\DevaluePhp\JavaScript\JsRegExp":private]=>
//     string(1) "g"
//   }
//   ["date"]=>
//   object(DateTime)#504 (3) {
//     ["date"]=>
//     string(26) "2023-01-16 00:00:00.000000"
//     ["timezone_type"]=>
//     int(2)
//     ["timezone"]=>
//     string(1) "Z"
//   }
//   ["autoConverted"]=>
//   enum(Maaaarcel\DevaluePhp\JavaScript\JsValue::PositiveInfinity)
//   ["undefined"]=>
//   enum(Maaaarcel\DevaluePhp\JavaScript\JsValue::Undefined)
//   ["normalNumber"]=>
//   int(1)
//   ["array"]=>
//   object(ArrayObject)#503 (1) {
//     ["storage":"ArrayObject":private]=>
//     array(2) {
//       [0]=>
//       object(Maaaarcel\DevaluePhp\JavaScript\JsBigInt)#501 (1) {
//         ["value":"Maaaarcel\DevaluePhp\JavaScript\JsBigInt":private]=>
//         int(1)
//       }
//       [1]=>
//       object(Maaaarcel\DevaluePhp\JavaScript\JsNumberObject)#500 (1) {
//         ["value":"Maaaarcel\DevaluePhp\JavaScript\JsNumberObject":private]=>
//         int(2)
//       }
//     }
//   }
// }

// if your devalue payload was inside a normal JSON string, you can use the value from json_decode with the `unflatten`
// method like so:

$json = '{
    "type": "data",
    "data": [{...devalue data...}]
}';
$payload = json_decode($json);

$data = Devalue::unflatten($payload->data);

// You can create custom types to transfer common objects. Custom types must implement the `DevalueSerializable` interface

use Maaaarcel\DevaluePhp\DevalueSerializable;

class CustomType implements DevalueSerializable
{

    public function __construct(
        public readonly string $field1 = '',
        public readonly string $field2 = ''
    )
    {
    }

    // specify the name of the type (used for parsing in the frontend library)
    static function devalueType(): string
    {
        return 'CustomType';
    }

    // create a class instance from the serialized data
    static function devalueParse(array $serialized): static
    {
        return new self($serialized['field1'], $serialized['field2']);
    }

    // serialize the data
    function devalueSerialize(): array
    {
        return [
            'field1' => $this->field1,
            'field2' => $this->field2
        ];
    }
}

$stringifiedCustomType = Devalue::stringify(new CustomType('foo', 'bar'));
// => '[["CustomType",1],{"field1":2,"field2":3},"foo","bar"]'

// To parse custom types, you can either specify your custom types globally, or individually for every parse.

// register type globally
Devalue::registerCustomTypes([CustomType::class]);

$parsedCustomType = Devalue::parse($stringifiedCustomType, [CustomType::class]); // register type only for this parse
// => class CustomType#552 (2) {
//   public readonly string $field1 =>
//   string(3) "foo"
//   public readonly string $field2 =>
//   string(3) "bar"
// }

Devalue::stringify可以处理以下数据类型

  • \Maaaarcel\DevaluePhp\JavaScript\JsBooleanObject
  • \Maaaarcel\DevaluePhp\JavaScript\JsNumberObject
  • \Maaaarcel\DevaluePhp\JavaScript\JsStringObject
  • \Maaaarcel\DevaluePhp\JavaScript\JsBigInt
  • \Maaaarcel\DevaluePhp\JavaScript\JsMap
  • \Maaaarcel\DevaluePhp\JavaScript\JsSet
  • \Maaaarcel\DevaluePhp\JavaScript\JsRegExp
  • int(如果数字大于9007199254740991,则自动转换为BigInt
  • float
  • string
  • bool
  • null
  • NAN(转换为NaN
  • INF(转换为Infinity / -Infinity
  • \DateTimeInterface(转换为Date()
  • \JsonSerializable(转换为JS对象)
  • \stdClass(转换为JS对象)
  • \ArrayObject(转换为JS数组)
  • [1, 2, 3] (list)(转换为JS数组)
  • ['a' => 1, 'b' => 2, 'c' => 3] (assoc array)(转换为JS对象)

Devalue::parseDevalue::unflatten方法将某些JavaScript值转换为对象/枚举值,以更准确地表示数据。这些对象/枚举值也可以在调用Devalue::stringify时用于传递这些JavaScript值。

以下是一个转换列表(左:JavaScript值,右:PHP值)

  • objects: \stdClass()
  • arrays: \ArrayObject()
  • Date(): \DateTime()
  • BigInt(): \Maaaarcel\DevaluePhp\JavaScript\JsBigInt()
  • Boolean(): \Maaaarcel\DevaluePhp\JavaScript\JsBooleanObject()
  • Number(): \Maaaarcel\DevaluePhp\JavaScript\JsNumberObject()
  • String(): \Maaaarcel\DevaluePhp\JavaScript\JsStringObject()
  • RegExp(): \Maaaarcel\DevaluePhp\JavaScript\JsRegExp()
  • Map(): \Maaaarcel\DevaluePhp\JavaScript\JsMap()
  • Set(): \Maaaarcel\DevaluePhp\JavaScript\JsSet()
  • undefined: \Maaaarcel\DevaluePhp\JavaScript\JsValue::Undefined
  • NaN: \Maaaarcel\DevaluePhp\JavaScript\JsValue::Nan
  • -0: \Maaaarcel\DevaluePhp\JavaScript\JsValue::NegativeZero
  • Infinity: \Maaaarcel\DevaluePhp\JavaScript\JsValue::PositiveInfinity
  • -Infinity: \Maaaarcel\DevaluePhp\JavaScript\JsValue::NegativeInfinity

在创建字符串之前,Stringify会转换一些特定的PHP值,以实现更好的兼容性和可用性

要在您的前端代码中消耗数据,您必须使用原始的devalue库。

性能

请查看当前提交的github action性能结果。基准测试使用phpbench运行

许可证

MIT