feat: remove deprecated Serializable interface

This commit is contained in:
Ben Ramsey
2022-04-01 16:40:08 -05:00
parent 13edf70fc9
commit dec678d60b
19 changed files with 217 additions and 361 deletions
+11 -3
View File
@@ -14,8 +14,6 @@ declare(strict_types=1);
namespace Ramsey\Uuid\Fields;
use Serializable;
/**
* UUIDs are comprised of unsigned integers, the bytes of which are separated
* into fields and arranged in a particular layout defined by the specification
@@ -23,8 +21,18 @@ use Serializable;
*
* @psalm-immutable
*/
interface FieldsInterface extends Serializable
interface FieldsInterface
{
/**
* @return mixed[]
*/
public function __serialize(): array;
/**
* @param mixed[] $data
*/
public function __unserialize(array $data): void;
/**
* Returns the bytes that comprise the fields
*/
+6 -29
View File
@@ -37,14 +37,6 @@ trait SerializableFieldsTrait
*/
abstract public function getBytes(): string;
/**
* Returns a string representation of object
*/
public function serialize(): string
{
return $this->getBytes();
}
/**
* @return array{bytes: string}
*/
@@ -54,33 +46,18 @@ trait SerializableFieldsTrait
}
/**
* Constructs the object from a serialized string representation
*
* @param string $serialized The serialized string representation of the object
*
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @psalm-suppress UnusedMethodCall
*/
public function unserialize($serialized): void
{
if (strlen($serialized) === 16) {
$this->__construct($serialized);
} else {
$this->__construct(base64_decode($serialized));
}
}
/**
* @param array{bytes: string} $data
* @param array{bytes?: string} $data
*/
public function __unserialize(array $data): void
{
// @codeCoverageIgnoreStart
if (!isset($data['bytes'])) {
throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__));
}
// @codeCoverageIgnoreEnd
$this->unserialize($data['bytes']);
if (strlen($data['bytes']) === 16) {
$this->__construct($data['bytes']);
} else {
$this->__construct(base64_decode($data['bytes']));
}
}
}
+3 -26
View File
@@ -87,15 +87,8 @@ final class LazyUuidFromString implements UuidInterface, TimeBasedInterface
);
}
public function serialize(): string
{
return $this->uuid;
}
/**
* @return array{string: string}
*
* @psalm-return array{string: non-empty-string}
* @return array{string: non-empty-string}
*/
public function __serialize(): array
{
@@ -103,31 +96,15 @@ final class LazyUuidFromString implements UuidInterface, TimeBasedInterface
}
/**
* {@inheritDoc}
*
* @param string $serialized
*
* @psalm-param non-empty-string $serialized
*/
public function unserialize($serialized): void
{
$this->uuid = $serialized;
}
/**
* @param array{string: string} $data
*
* @psalm-param array{string: non-empty-string} $data
* @param array{string?: non-empty-string} $data
*/
public function __unserialize(array $data): void
{
// @codeCoverageIgnoreStart
if (!isset($data['string'])) {
throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__));
}
// @codeCoverageIgnoreEnd
$this->unserialize($data['string']);
$this->uuid = $data['string'];
}
public function getDateTime(): DateTimeInterface
+40 -56
View File
@@ -35,44 +35,15 @@ use function sprintf;
final class Decimal implements NumberInterface
{
/**
* @var string
* @var numeric-string
*/
private $value;
private string $value;
/**
* @var bool
*/
private $isNegative = false;
private bool $isNegative = false;
/**
* @param mixed $value The decimal value to store
*/
public function __construct($value)
public function __construct(float | int | self | string $value)
{
$value = (string) $value;
if (!is_numeric($value)) {
throw new InvalidArgumentException(
'Value must be a signed decimal or a string containing only '
. 'digits 0-9 and, optionally, a decimal point or sign (+ or -)'
);
}
// Remove the leading +-symbol.
if (strpos($value, '+') === 0) {
$value = substr($value, 1);
}
// For cases like `-0` or `-0.0000`, convert the value to `0`.
if (abs((float) $value) === 0.0) {
$value = '0';
}
if (strpos($value, '-') === 0) {
$this->isNegative = true;
}
$this->value = $value;
$this->value = $value instanceof self ? (string) $value : $this->prepareValue($value);
}
public function isNegative(): bool
@@ -95,11 +66,6 @@ final class Decimal implements NumberInterface
return $this->toString();
}
public function serialize(): string
{
return $this->toString();
}
/**
* @return array{string: string}
*/
@@ -109,29 +75,47 @@ final class Decimal implements NumberInterface
}
/**
* Constructs the object from a serialized string representation
*
* @param string $serialized The serialized string representation of the object
*
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @psalm-suppress UnusedMethodCall
*/
public function unserialize($serialized): void
{
$this->__construct($serialized);
}
/**
* @param array{string: string} $data
* @param array{string?: string} $data
*/
public function __unserialize(array $data): void
{
// @codeCoverageIgnoreStart
if (!isset($data['string'])) {
throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__));
}
// @codeCoverageIgnoreEnd
$this->unserialize($data['string']);
$this->value = $this->prepareValue($data['string']);
}
/**
* @return numeric-string
*/
private function prepareValue(float | int | string $value): string
{
$value = (string) $value;
if (!is_numeric($value)) {
throw new InvalidArgumentException(
'Value must be a signed decimal or a string containing only '
. 'digits 0-9 and, optionally, a decimal point or sign (+ or -)'
);
}
// Remove the leading +-symbol.
if (str_starts_with($value, '+')) {
$value = substr($value, 1);
}
// For cases like `-0` or `-0.0000`, convert the value to `0`.
if (abs((float) $value) === 0.0) {
$value = '0';
}
if (str_starts_with($value, '-')) {
$this->isNegative = true;
}
assert(is_numeric($value));
return $value;
}
}
+24 -42
View File
@@ -19,7 +19,7 @@ use ValueError;
use function ctype_xdigit;
use function sprintf;
use function strpos;
use function str_starts_with;
use function strtolower;
use function substr;
@@ -34,29 +34,14 @@ use function substr;
*/
final class Hexadecimal implements TypeInterface
{
/**
* @var string
*/
private $value;
private string $value;
/**
* @param string $value The hexadecimal value to store
* @param string | self $value The hexadecimal value to store
*/
public function __construct(string $value)
public function __construct(self | string $value)
{
$value = strtolower($value);
if (strpos($value, '0x') === 0) {
$value = substr($value, 2);
}
if (!ctype_xdigit($value)) {
throw new InvalidArgumentException(
'Value must be a hexadecimal number'
);
}
$this->value = $value;
$this->value = $value instanceof self ? (string) $value : $this->prepareValue($value);
}
public function toString(): string
@@ -74,11 +59,6 @@ final class Hexadecimal implements TypeInterface
return $this->toString();
}
public function serialize(): string
{
return $this->toString();
}
/**
* @return array{string: string}
*/
@@ -88,29 +68,31 @@ final class Hexadecimal implements TypeInterface
}
/**
* Constructs the object from a serialized string representation
*
* @param string $serialized The serialized string representation of the object
*
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @psalm-suppress UnusedMethodCall
*/
public function unserialize($serialized): void
{
$this->__construct($serialized);
}
/**
* @param array{string: string} $data
* @param array{string?: string} $data
*/
public function __unserialize(array $data): void
{
// @codeCoverageIgnoreStart
if (!isset($data['string'])) {
throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__));
}
// @codeCoverageIgnoreEnd
$this->unserialize($data['string']);
$this->value = $this->prepareValue($data['string']);
}
private function prepareValue(string $value): string
{
$value = strtolower($value);
if (str_starts_with($value, '0x')) {
$value = substr($value, 2);
}
if (!ctype_xdigit($value)) {
throw new InvalidArgumentException(
'Value must be a hexadecimal number'
);
}
return $value;
}
}
+62 -73
View File
@@ -17,10 +17,12 @@ namespace Ramsey\Uuid\Type;
use Ramsey\Uuid\Exception\InvalidArgumentException;
use ValueError;
use function assert;
use function ctype_digit;
use function is_numeric;
use function ltrim;
use function sprintf;
use function strpos;
use function str_starts_with;
use function substr;
/**
@@ -40,23 +42,74 @@ final class Integer implements NumberInterface
/**
* @psalm-var numeric-string
*/
private $value;
private string $value;
private bool $isNegative = false;
public function __construct(float | int | self | string $value)
{
$this->value = $value instanceof self ? (string) $value : $this->prepareValue($value);
}
public function isNegative(): bool
{
return $this->isNegative;
}
/**
* @var bool
* @psalm-return numeric-string
*/
private $isNegative = false;
public function toString(): string
{
return $this->value;
}
/**
* @param mixed $value The integer value to store
* @psalm-return numeric-string
*/
public function __construct($value)
public function __toString(): string
{
return $this->toString();
}
/**
* @psalm-return numeric-string
*/
public function jsonSerialize(): string
{
return $this->toString();
}
/**
* @return array{string: string}
*/
public function __serialize(): array
{
return ['string' => $this->toString()];
}
/**
* @param array{string?: string} $data
*/
public function __unserialize(array $data): void
{
if (!isset($data['string'])) {
throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__));
}
$this->value = $this->prepareValue($data['string']);
}
/**
* @return numeric-string
*/
private function prepareValue(float | int | string $value): string
{
$value = (string) $value;
$sign = '+';
// If the value contains a sign, remove it for ctype_digit() check.
if (strpos($value, '-') === 0 || strpos($value, '+') === 0) {
if (str_starts_with($value, '-') || str_starts_with($value, '+')) {
$sign = substr($value, 0, 1);
$value = substr($value, 1);
}
@@ -82,72 +135,8 @@ final class Integer implements NumberInterface
$this->isNegative = true;
}
/** @psalm-var numeric-string $numericValue */
$numericValue = $value;
assert(is_numeric($value));
$this->value = $numericValue;
}
public function isNegative(): bool
{
return $this->isNegative;
}
/**
* @psalm-return numeric-string
*/
public function toString(): string
{
return $this->value;
}
public function __toString(): string
{
return $this->toString();
}
public function jsonSerialize(): string
{
return $this->toString();
}
public function serialize(): string
{
return $this->toString();
}
/**
* @return array{string: string}
*/
public function __serialize(): array
{
return ['string' => $this->toString()];
}
/**
* Constructs the object from a serialized string representation
*
* @param string $serialized The serialized string representation of the object
*
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @psalm-suppress UnusedMethodCall
*/
public function unserialize($serialized): void
{
$this->__construct($serialized);
}
/**
* @param array{string: string} $data
*/
public function __unserialize(array $data): void
{
// @codeCoverageIgnoreStart
if (!isset($data['string'])) {
throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__));
}
// @codeCoverageIgnoreEnd
$this->unserialize($data['string']);
return $value;
}
}
+11 -52
View File
@@ -14,13 +14,9 @@ declare(strict_types=1);
namespace Ramsey\Uuid\Type;
use Ramsey\Uuid\Exception\UnsupportedOperationException;
use Ramsey\Uuid\Type\Integer as IntegerObject;
use ValueError;
use stdClass;
use function json_decode;
use function json_encode;
use function sprintf;
/**
@@ -34,24 +30,15 @@ use function sprintf;
*/
final class Time implements TypeInterface
{
/**
* @var IntegerObject
*/
private $seconds;
private IntegerObject $seconds;
private IntegerObject $microseconds;
/**
* @var IntegerObject
*/
private $microseconds;
/**
* @param mixed $seconds
* @param mixed $microseconds
*/
public function __construct($seconds, $microseconds = 0)
{
$this->seconds = new IntegerObject($seconds);
$this->microseconds = new IntegerObject($microseconds);
public function __construct(
int | string | IntegerObject $seconds,
int | string | IntegerObject $microseconds = new IntegerObject(0),
) {
$this->seconds = $seconds instanceof IntegerObject ? $seconds : new IntegerObject($seconds);
$this->microseconds = $microseconds instanceof IntegerObject ? $microseconds : new IntegerObject($microseconds);
}
public function getSeconds(): IntegerObject
@@ -85,11 +72,6 @@ final class Time implements TypeInterface
];
}
public function serialize(): string
{
return (string) json_encode($this);
}
/**
* @return array{seconds: string, microseconds: string}
*/
@@ -102,38 +84,15 @@ final class Time implements TypeInterface
}
/**
* Constructs the object from a serialized string representation
*
* @param string $serialized The serialized string representation of the object
*
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @psalm-suppress UnusedMethodCall
*/
public function unserialize($serialized): void
{
/** @var stdClass $time */
$time = json_decode($serialized);
if (!isset($time->seconds) || !isset($time->microseconds)) {
throw new UnsupportedOperationException(
'Attempted to unserialize an invalid value'
);
}
$this->__construct($time->seconds, $time->microseconds);
}
/**
* @param array{seconds: string, microseconds: string} $data
* @param array{seconds?: string, microseconds?: string} $data
*/
public function __unserialize(array $data): void
{
// @codeCoverageIgnoreStart
if (!isset($data['seconds']) || !isset($data['microseconds'])) {
throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__));
}
// @codeCoverageIgnoreEnd
$this->__construct($data['seconds'], $data['microseconds']);
$this->seconds = new IntegerObject($data['seconds']);
$this->microseconds = new IntegerObject($data['microseconds']);
}
}
+11 -2
View File
@@ -15,15 +15,24 @@ declare(strict_types=1);
namespace Ramsey\Uuid\Type;
use JsonSerializable;
use Serializable;
/**
* TypeInterface ensures consistency in typed values returned by ramsey/uuid
*
* @psalm-immutable
*/
interface TypeInterface extends JsonSerializable, Serializable
interface TypeInterface extends JsonSerializable
{
/**
* @return mixed[]
*/
public function __serialize(): array;
/**
* @param mixed[] $data
*/
public function __unserialize(array $data): void;
public function toString(): string;
public function __toString(): string;
+10 -33
View File
@@ -253,38 +253,29 @@ class Uuid implements Rfc4122UuidInterface
return $this->toString();
}
/**
* Converts the UUID to a string for PHP serialization
*/
public function serialize(): string
{
return $this->getFields()->getBytes();
}
/**
* @return array{bytes: string}
*/
public function __serialize(): array
{
return ['bytes' => $this->serialize()];
return ['bytes' => $this->getFields()->getBytes()];
}
/**
* Re-constructs the object from its serialized form
*
* @param string $serialized The serialized PHP string to unserialize into
* a UuidInterface instance
*
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param array{bytes?: string} $data
*/
public function unserialize($serialized): void
public function __unserialize(array $data): void
{
if (strlen($serialized) === 16) {
if (!isset($data['bytes'])) {
throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__));
}
if (strlen($data['bytes']) === 16) {
/** @var Uuid $uuid */
$uuid = self::getFactory()->fromBytes($serialized);
$uuid = self::getFactory()->fromBytes($data['bytes']);
} else {
/** @var Uuid $uuid */
$uuid = self::getFactory()->fromString($serialized);
$uuid = self::getFactory()->fromString($data['bytes']);
}
$this->codec = $uuid->codec;
@@ -293,20 +284,6 @@ class Uuid implements Rfc4122UuidInterface
$this->timeConverter = $uuid->timeConverter;
}
/**
* @param array{bytes: string} $data
*/
public function __unserialize(array $data): void
{
// @codeCoverageIgnoreStart
if (!isset($data['bytes'])) {
throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__));
}
// @codeCoverageIgnoreEnd
$this->unserialize($data['bytes']);
}
public function compareTo(UuidInterface $other): int
{
$compare = strcmp($this->toString(), $other->toString());
+11 -2
View File
@@ -18,7 +18,6 @@ use JsonSerializable;
use Ramsey\Uuid\Fields\FieldsInterface;
use Ramsey\Uuid\Type\Hexadecimal;
use Ramsey\Uuid\Type\Integer as IntegerObject;
use Serializable;
/**
* A UUID is a universally unique identifier adhering to an agreed-upon
@@ -26,8 +25,18 @@ use Serializable;
*
* @psalm-immutable
*/
interface UuidInterface extends JsonSerializable, Serializable
interface UuidInterface extends JsonSerializable
{
/**
* @return mixed[]
*/
public function __serialize(): array;
/**
* @param mixed[] $data
*/
public function __unserialize(array $data): void;
/**
* Returns -1, 0, or 1 if the UUID is less than, equal to, or greater than
* the other UUID
+6
View File
@@ -1,5 +1,11 @@
<?php
/**
* phpcs:disable Generic.PHP.DiscourageGoto.Found
* phpcs:disable Generic.WhiteSpace.ScopeIndent.IncorrectExact
* phpcs:disable Generic.WhiteSpace.ScopeIndent.Incorrect
*/
declare(strict_types=1);
namespace Ramsey\Uuid;
+3 -1
View File
@@ -177,11 +177,13 @@ class ExpectedBehaviorTest extends TestCase
/**
* @dataProvider provideFromStringInteger
*/
public function testSerialization($string)
public function testSerialization(string $string): void
{
$uuid = Uuid::fromString($string);
$serialized = serialize($uuid);
/** @var UuidInterface $unserialized */
$unserialized = unserialize($serialized);
$this->assertSame(0, $uuid->compareTo($unserialized));
+2
View File
@@ -197,6 +197,8 @@ class FieldsTest extends TestCase
$fields = new Fields($bytes);
$serializedFields = serialize($fields);
/** @var Fields $unserializedFields */
$unserializedFields = unserialize($serializedFields);
$this->assertSame($fields->getBytes(), $unserializedFields->getBytes());
+2
View File
@@ -72,6 +72,8 @@ class FieldsTest extends TestCase
$fields = new Fields($bytes);
$serializedFields = serialize($fields);
/** @var Fields $unserializedFields */
$unserializedFields = unserialize($serializedFields);
$this->assertSame($fields->getBytes(), $unserializedFields->getBytes());
+1 -9
View File
@@ -208,16 +208,8 @@ class FieldsTest extends TestCase
$fields = new Fields($bytes);
$serializedFields = serialize($fields);
$unserializedFields = unserialize($serializedFields);
$this->assertSame($fields->getBytes(), $unserializedFields->getBytes());
}
public function testSerializingFieldsWithOldFormat(): void
{
$fields = new Fields("\xb3\xcd\x58\x6a\xe3\xca\x44\xf3\x98\x8c\xf4\xd6\x66\xc1\xbf\x4d");
$serializedFields = 'C:26:"Ramsey\Uuid\Rfc4122\Fields":24:{s81YauPKRPOYjPTWZsG/TQ==}';
/** @var Fields $unserializedFields */
$unserializedFields = unserialize($serializedFields);
$this->assertSame($fields->getBytes(), $unserializedFields->getBytes());
+3 -3
View File
@@ -275,14 +275,14 @@ class DecimalTest extends TestCase
}
/**
* @param mixed $value
*
* @dataProvider provideDecimal
*/
public function testSerializeUnserializeDecimal($value, string $expected): void
public function testSerializeUnserializeDecimal(float | int | Decimal | string $value, string $expected): void
{
$decimal = new Decimal($value);
$serializedDecimal = serialize($decimal);
/** @var Decimal $unserializedDecimal */
$unserializedDecimal = unserialize($serializedDecimal);
$this->assertSame($expected, $unserializedDecimal->toString());
+3 -3
View File
@@ -74,14 +74,14 @@ class HexadecimalTest extends TestCase
}
/**
* @param mixed $value
*
* @dataProvider provideHex
*/
public function testSerializeUnserializeHexadecimal($value, string $expected): void
public function testSerializeUnserializeHexadecimal(Hexadecimal | string $value, string $expected): void
{
$hexadecimal = new Hexadecimal($value);
$serializedHexadecimal = serialize($hexadecimal);
/** @var Hexadecimal $unserializedHexadecimal */
$unserializedHexadecimal = unserialize($serializedHexadecimal);
$this->assertSame($expected, $unserializedHexadecimal->toString());
+7 -19
View File
@@ -62,13 +62,12 @@ class TimeTest extends TestCase
}
/**
* @param int|float|string $seconds
* @param int|float|string|null $microseconds
*
* @dataProvider provideTimeValues
*/
public function testSerializeUnserializeTime($seconds, $microseconds): void
{
public function testSerializeUnserializeTime(
int | IntegerObject | string $seconds,
int | IntegerObject | string | null $microseconds
): void {
$params = [$seconds];
if ($microseconds !== null) {
$params[] = $microseconds;
@@ -76,6 +75,8 @@ class TimeTest extends TestCase
$time = new Time(...$params);
$serializedTime = serialize($time);
/** @var Time $unserializedTime */
$unserializedTime = unserialize($serializedTime);
$this->assertSame((string) $seconds, $unserializedTime->getSeconds()->toString());
@@ -86,23 +87,10 @@ class TimeTest extends TestCase
);
}
public function testUnserializeOfInvalidValueException(): void
{
$invalidSerialization = 'C:21:"Ramsey\\Uuid\\Type\\Time":13:{{"foo":"bar"}}';
$this->expectException(UnsupportedOperationException::class);
$this->expectExceptionMessage('Attempted to unserialize an invalid value');
unserialize($invalidSerialization);
}
/**
* @param int|float|string $seconds
* @param int|float|string|null $microseconds
*
* @dataProvider provideTimeValues
*/
public function testJsonSerialize($seconds, $microseconds): void
public function testJsonSerialize(int | IntegerObject | string $seconds, int | IntegerObject | string | null $microseconds): void
{
$time = [
'seconds' => (string) $seconds,
+1 -8
View File
@@ -1472,18 +1472,11 @@ class UuidTest extends TestCase
{
$uuid = Uuid::uuid4();
$serialized = serialize($uuid);
$unserializedUuid = unserialize($serialized);
$this->assertTrue($uuid->equals($unserializedUuid));
}
public function testSerializeWithOldStringFormat(): void
{
$serialized = 'C:26:"Ramsey\Uuid\Rfc4122\UuidV4":36:{b3cd586a-e3ca-44f3-988c-f4d666c1bf4d}';
/** @var UuidInterface $unserializedUuid */
$unserializedUuid = unserialize($serialized);
$this->assertSame('b3cd586a-e3ca-44f3-988c-f4d666c1bf4d', $unserializedUuid->toString());
$this->assertTrue($uuid->equals($unserializedUuid));
}
public function testUuid3WithEmptyNamespace(): void