14
14
final class EmojiTransliterator extends \Transliterator
15
15
{
16
16
private array $ map ;
17
+ private \Transliterator $ transliterator ;
17
18
18
19
public static function create (string $ id , int $ direction = self ::FORWARD ): ?\Transliterator
19
20
{
20
21
if (self ::REVERSE === $ direction ) {
21
- return \Transliterator::createFromRules ('A > B ' )->createInverse ();
22
+ // Create a failing reverse-transliterator to populate intl_get_error_*()
23
+ \Transliterator::createFromRules ('A > B ' )->createInverse ();
24
+
25
+ throw new \IntlException (intl_get_error_message (), intl_get_error_code ());
22
26
}
23
27
$ id = strtolower ($ id );
24
28
25
29
if (!preg_match ('/^[a-z0-9@_ \\. \\-]*$/ ' , $ id )) {
26
- return \Transliterator::create ($ id );
30
+ \Transliterator::create ('Emoji: ' .$ id );
31
+
32
+ throw new \IntlException (intl_get_error_message (), intl_get_error_code ());
27
33
}
28
34
29
35
if (!is_file (\dirname (__DIR__ )."/Resources/data/transliterator/emoji/ {$ id }.php " )) {
30
- return \Transliterator::create ($ id );
36
+ // Populate intl_get_error_*()
37
+ \Transliterator::create ('Emoji: ' .$ id );
38
+
39
+ throw new \IntlException (intl_get_error_message (), intl_get_error_code ());
31
40
}
32
41
42
+ // Create an instance of \Transliterator with a custom id; that's the only way
33
43
$ instance = unserialize (sprintf ('O:%d:"%s":1:{s:2:"id";s:%d:"%s";} ' , \strlen (self ::class), self ::class, \strlen ($ id ), $ id ));
34
44
$ instance ->map = require \dirname (__DIR__ )."/Resources/data/transliterator/emoji/ {$ id }.php " ;
35
45
@@ -38,17 +48,18 @@ public static function create(string $id, int $direction = self::FORWARD): ?\Tra
38
48
39
49
public function createInverse (): ?self
40
50
{
51
+ // Create a failing reverse-transliterator to populate intl_get_error_*()
41
52
return \Transliterator::createFromRules ('A > B ' )->createInverse ();
42
53
}
43
54
44
55
public function getErrorCode (): int |false
45
56
{
46
- return $ this ->transliterator ?->getErrorCode() ?? false ;
57
+ return $ this ->transliterator ?->getErrorCode() ?? 0 ;
47
58
}
48
59
49
60
public function getErrorMessage (): string |false
50
61
{
51
- return $ this ->transliterator ->getErrorMessage () ?? false ;
62
+ return $ this ->transliterator ? ->getErrorMessage() ?? false ;
52
63
}
53
64
54
65
public static function listIDs (): array |false
@@ -68,18 +79,20 @@ public static function listIDs(): array|false
68
79
69
80
public function transliterate (string $ string , int $ start = 0 , int $ end = -1 ): string |false
70
81
{
82
+ // Here we rely on intl to validate the $string, $start and $end arguments
83
+ // and to slice the string. Slicing is done by replacing the part if $string
84
+ // between $start and $end by a unique cookie that can be reliably used to
85
+ // identify which part of $string should be transliterated.
86
+
71
87
static $ cookie ;
72
88
static $ transliterator ;
73
89
74
90
$ cookie ??= md5 (random_bytes (8 ));
75
- $ transliterator ??= \Transliterator::createFromRules ('[:any:]* > ' .$ cookie );
91
+ $ this -> transliterator ??= clone $ transliterator ??= \Transliterator::createFromRules ('[:any:]* > ' .$ cookie );
76
92
77
- if (false === $ result = $ transliterator ->transliterate ($ string , $ start , $ end )) {
93
+ if (false === $ result = $ this -> transliterator ->transliterate ($ string , $ start , $ end )) {
78
94
return false ;
79
95
}
80
- if (4 > \strlen ($ string )) {
81
- return $ string ;
82
- }
83
96
$ map = $ this ->map ;
84
97
85
98
if ($ cookie === $ result ) {
0 commit comments