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