Skip to content

Commit 4000e89

Browse files
committed
refactor: remove dependency on ext-ctype
1 parent 59414d4 commit 4000e89

8 files changed

+78
-69
lines changed

.github/workflows/continuous-integration.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ jobs:
9191
uses: "shivammathur/setup-php@v2"
9292
with:
9393
php-version: "${{ matrix.php-version }}"
94-
extensions: bcmath, ctype, gmp, sodium, uuid
94+
extensions: bcmath, gmp, sodium, uuid
9595
coverage: "none"
9696
ini-values: "memory_limit=-1"
9797

@@ -118,7 +118,7 @@ jobs:
118118
uses: "shivammathur/setup-php@v2"
119119
with:
120120
php-version: "latest"
121-
extensions: bcmath, ctype, gmp, sodium, uuid
121+
extensions: bcmath, gmp, sodium, uuid
122122
coverage: "pcov"
123123
ini-values: "memory_limit=-1"
124124

@@ -168,7 +168,7 @@ jobs:
168168
uses: "shivammathur/setup-php@v2"
169169
with:
170170
php-version: "${{ matrix.php-version }}"
171-
extensions: bcmath, ctype, gmp, sodium, uuid
171+
extensions: bcmath, gmp, sodium, uuid
172172
coverage: "none"
173173
ini-values: "memory_limit=-1"
174174

composer.json

-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
],
1111
"require": {
1212
"php": "^8.0",
13-
"ext-ctype": "*",
1413
"ext-json": "*",
1514
"brick/math": "^0.8.8 || ^0.9 || ^0.10",
1615
"ramsey/collection": "^1.0"
@@ -42,7 +41,6 @@
4241
},
4342
"suggest": {
4443
"ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.",
45-
"ext-ctype": "Enables faster processing of character classification using ctype functions.",
4644
"ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.",
4745
"ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.",
4846
"paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter",

composer.lock

+1-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/quickstart.rst

-3
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ Requirements
1111
ramsey/uuid |version| requires the following:
1212

1313
* PHP 8.0+
14-
* `ext-ctype <https://www.php.net/manual/en/book.ctype.php>`_ or a polyfill that
15-
provides ext-ctype, such as `symfony/polyfill-ctype
16-
<https://packagist.org/packages/symfony/polyfill-ctype>`_
1714
* `ext-json <https://www.php.net/manual/en/book.json.php>`_
1815

1916
The JSON extension is normally enabled by default, but it is possible to disable

src/Generator/DefaultTimeGenerator.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@
2323
use Ramsey\Uuid\Type\Hexadecimal;
2424
use Throwable;
2525

26-
use function ctype_xdigit;
2726
use function dechex;
2827
use function hex2bin;
2928
use function is_int;
3029
use function pack;
30+
use function preg_match;
3131
use function sprintf;
3232
use function str_pad;
3333
use function strlen;
@@ -120,7 +120,7 @@ private function getValidNode(int | string | null $node): string
120120
$node = dechex($node);
121121
}
122122

123-
if (!ctype_xdigit((string) $node) || strlen((string) $node) > 12) {
123+
if (!preg_match('/^[A-Fa-f0-9]+$/', (string) $node) || strlen((string) $node) > 12) {
124124
throw new InvalidArgumentException('Invalid node value');
125125
}
126126

src/Type/Hexadecimal.php

+21-18
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,8 @@
1717
use Ramsey\Uuid\Exception\InvalidArgumentException;
1818
use ValueError;
1919

20-
use function ctype_xdigit;
20+
use function preg_match;
2121
use function sprintf;
22-
use function str_starts_with;
23-
use function strtolower;
2422
use function substr;
2523

2624
/**
@@ -37,23 +35,11 @@ final class Hexadecimal implements TypeInterface
3735
private string $value;
3836

3937
/**
40-
* @param string $value The hexadecimal value to store
38+
* @param self|string $value The hexadecimal value to store
4139
*/
42-
public function __construct(string $value)
40+
public function __construct(self | string $value)
4341
{
44-
$value = strtolower($value);
45-
46-
if (str_starts_with($value, '0x')) {
47-
$value = substr($value, 2);
48-
}
49-
50-
if (!ctype_xdigit($value)) {
51-
throw new InvalidArgumentException(
52-
'Value must be a hexadecimal number'
53-
);
54-
}
55-
56-
$this->value = $value;
42+
$this->value = $value instanceof self ? (string) $value : $this->prepareValue($value);
5743
}
5844

5945
public function toString(): string
@@ -109,4 +95,21 @@ public function __unserialize(array $data): void
10995

11096
$this->unserialize($data['string']);
11197
}
98+
99+
private function prepareValue(string $value): string
100+
{
101+
$value = strtolower($value);
102+
103+
if (str_starts_with($value, '0x')) {
104+
$value = substr($value, 2);
105+
}
106+
107+
if (!preg_match('/^[A-Fa-f0-9]+$/', $value)) {
108+
throw new InvalidArgumentException(
109+
'Value must be a hexadecimal number'
110+
);
111+
}
112+
113+
return $value;
114+
}
112115
}

src/Type/Integer.php

+49-37
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@
1717
use Ramsey\Uuid\Exception\InvalidArgumentException;
1818
use ValueError;
1919

20-
use function ctype_digit;
21-
use function ltrim;
20+
use function assert;
21+
use function is_numeric;
22+
use function preg_match;
2223
use function sprintf;
23-
use function str_starts_with;
2424
use function substr;
2525

2626
/**
@@ -46,40 +46,7 @@ final class Integer implements NumberInterface
4646

4747
public function __construct(float | int | string | self $value)
4848
{
49-
$value = (string) $value;
50-
$sign = '+';
51-
52-
// If the value contains a sign, remove it for ctype_digit() check.
53-
if (str_starts_with($value, '-') || str_starts_with($value, '+')) {
54-
$sign = substr($value, 0, 1);
55-
$value = substr($value, 1);
56-
}
57-
58-
if (!ctype_digit($value)) {
59-
throw new InvalidArgumentException(
60-
'Value must be a signed integer or a string containing only '
61-
. 'digits 0-9 and, optionally, a sign (+ or -)'
62-
);
63-
}
64-
65-
// Trim any leading zeros.
66-
$value = ltrim($value, '0');
67-
68-
// Set to zero if the string is empty after trimming zeros.
69-
if ($value === '') {
70-
$value = '0';
71-
}
72-
73-
// Add the negative sign back to the value.
74-
if ($sign === '-' && $value !== '0') {
75-
$value = $sign . $value;
76-
$this->isNegative = true;
77-
}
78-
79-
/** @psalm-var numeric-string $numericValue */
80-
$numericValue = $value;
81-
82-
$this->value = $numericValue;
49+
$this->value = $value instanceof self ? (string) $value : $this->prepareValue($value);
8350
}
8451

8552
public function isNegative(): bool
@@ -95,6 +62,9 @@ public function toString(): string
9562
return $this->value;
9663
}
9764

65+
/**
66+
* @psalm-return numeric-string
67+
*/
9868
public function __toString(): string
9969
{
10070
return $this->toString();
@@ -143,4 +113,46 @@ public function __unserialize(array $data): void
143113

144114
$this->unserialize($data['string']);
145115
}
116+
117+
/**
118+
* @return numeric-string
119+
*/
120+
private function prepareValue(float | int | string $value): string
121+
{
122+
$value = (string) $value;
123+
$sign = '+';
124+
125+
// If the value contains a sign, remove it for digit pattern check.
126+
if (str_starts_with($value, '-') || str_starts_with($value, '+')) {
127+
$sign = substr($value, 0, 1);
128+
$value = substr($value, 1);
129+
}
130+
131+
if (!preg_match('/^\d+$/', $value)) {
132+
throw new InvalidArgumentException(
133+
'Value must be a signed integer or a string containing only '
134+
. 'digits 0-9 and, optionally, a sign (+ or -)'
135+
);
136+
}
137+
138+
// Trim any leading zeros.
139+
$value = ltrim($value, '0');
140+
141+
// Set to zero if the string is empty after trimming zeros.
142+
if ($value === '') {
143+
$value = '0';
144+
}
145+
146+
// Add the negative sign back to the value.
147+
if ($sign === '-' && $value !== '0') {
148+
$value = $sign . $value;
149+
150+
/** @psalm-suppress InaccessibleProperty */
151+
$this->isNegative = true;
152+
}
153+
154+
assert(is_numeric($value));
155+
156+
return $value;
157+
}
146158
}

tests/ExpectedBehaviorTest.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ public function testStaticCreationMethodsAndStandardBehavior($method, $args)
119119

120120
$this->assertSame(2, $uuid->getVariant());
121121
$this->assertSame((int) substr($method, -1), $uuid->getVersion());
122-
$this->assertTrue(ctype_digit((string) $uuid->getInteger()));
122+
$this->assertSame(1, preg_match('/^\d+$/', (string) $uuid->getInteger()));
123123
}
124124

125125
public function provideStaticCreationMethods()
@@ -158,7 +158,7 @@ public function testUuidVersion1MethodBehavior64Bit()
158158
$this->assertSame('281474976710655', (string) $uuid->getNode());
159159
$this->assertSame('3fff', $uuid->getClockSequenceHex());
160160
$this->assertSame('16383', (string) $uuid->getClockSequence());
161-
$this->assertTrue(ctype_digit((string) $uuid->getTimestamp()));
161+
$this->assertSame(1, preg_match('/^\d+$/', (string) $uuid->getTimestamp()));
162162
}
163163

164164
/**

0 commit comments

Comments
 (0)