1<?php
2
3/**
4 * This file is part of the ramsey/uuid library
5 *
6 * For the full copyright and license information, please view the LICENSE
7 * file that was distributed with this source code.
8 *
9 * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
10 * @license http://opensource.org/licenses/MIT MIT
11 */
12
13declare(strict_types=1);
14
15namespace Ramsey\Uuid\Type;
16
17use Ramsey\Uuid\Exception\InvalidArgumentException;
18use ValueError;
19
20use function ctype_digit;
21use function ltrim;
22use function sprintf;
23use function strpos;
24use function substr;
25
26/**
27 * A value object representing an integer
28 *
29 * This class exists for type-safety purposes, to ensure that integers
30 * returned from ramsey/uuid methods as strings are truly integers and not some
31 * other kind of string.
32 *
33 * To support large integers beyond PHP_INT_MAX and PHP_INT_MIN on both 64-bit
34 * and 32-bit systems, we store the integers as strings.
35 *
36 * @psalm-immutable
37 */
38final class Integer implements NumberInterface
39{
40    /**
41     * @psalm-var numeric-string
42     */
43    private $value;
44
45    /**
46     * @var bool
47     */
48    private $isNegative = false;
49
50    /**
51     * @param mixed $value The integer value to store
52     */
53    public function __construct($value)
54    {
55        $value = (string) $value;
56        $sign = '+';
57
58        // If the value contains a sign, remove it for ctype_digit() check.
59        if (strpos($value, '-') === 0 || strpos($value, '+') === 0) {
60            $sign = substr($value, 0, 1);
61            $value = substr($value, 1);
62        }
63
64        if (!ctype_digit($value)) {
65            throw new InvalidArgumentException(
66                'Value must be a signed integer or a string containing only '
67                . 'digits 0-9 and, optionally, a sign (+ or -)'
68            );
69        }
70
71        // Trim any leading zeros.
72        $value = ltrim($value, '0');
73
74        // Set to zero if the string is empty after trimming zeros.
75        if ($value === '') {
76            $value = '0';
77        }
78
79        // Add the negative sign back to the value.
80        if ($sign === '-' && $value !== '0') {
81            $value = $sign . $value;
82            $this->isNegative = true;
83        }
84
85        /** @psalm-var numeric-string $numericValue */
86        $numericValue = $value;
87
88        $this->value = $numericValue;
89    }
90
91    public function isNegative(): bool
92    {
93        return $this->isNegative;
94    }
95
96    /**
97     * @psalm-return numeric-string
98     */
99    public function toString(): string
100    {
101        return $this->value;
102    }
103
104    public function __toString(): string
105    {
106        return $this->toString();
107    }
108
109    public function jsonSerialize(): string
110    {
111        return $this->toString();
112    }
113
114    public function serialize(): string
115    {
116        return $this->toString();
117    }
118
119    /**
120     * @return array{string: string}
121     */
122    public function __serialize(): array
123    {
124        return ['string' => $this->toString()];
125    }
126
127    /**
128     * Constructs the object from a serialized string representation
129     *
130     * @param string $serialized The serialized string representation of the object
131     *
132     * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
133     * @psalm-suppress UnusedMethodCall
134     */
135    public function unserialize($serialized): void
136    {
137        $this->__construct($serialized);
138    }
139
140    /**
141     * @param array{string: string} $data
142     */
143    public function __unserialize(array $data): void
144    {
145        // @codeCoverageIgnoreStart
146        if (!isset($data['string'])) {
147            throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__));
148        }
149        // @codeCoverageIgnoreEnd
150
151        $this->unserialize($data['string']);
152    }
153}
154