1515 *
1616 * - `\` escapes other special characters if usage of escape character is not turned off.
1717 * - `*` matches any string including the empty string except it has a delimiter (`/` and `\` by default).
18- * - `**` matches any string including the empty string and delimiters.
18+ * - `**` matches any string including the empty string and delimiters.
1919 * - `?` matches any single character.
2020 * - `[seq]` matches any character in seq.
2121 * - `[a-z]` matches any character from a to z.
@@ -27,6 +27,11 @@ final class WildcardPattern
2727{
2828 private bool $ ignoreCase = false ;
2929
30+ /**
31+ * @psalm-var non-empty-string|null
32+ */
33+ private ?string $ patternPrepared = null ;
34+
3035 /**
3136 * @param string $pattern The shell wildcard pattern to match against.
3237 * @param string[] $delimiters Delimiters to consider for "*" (`/` and `\` by default).
@@ -50,7 +55,55 @@ public function match(string $string): bool
5055 return true ;
5156 }
5257
53- $ pattern = $ this ->pattern ;
58+ return preg_match ($ this ->getPatternPrepared (), $ string ) === 1 ;
59+ }
60+
61+ /**
62+ * Make pattern case insensitive.
63+ */
64+ public function ignoreCase (bool $ flag = true ): self
65+ {
66+ $ new = clone $ this ;
67+ $ new ->patternPrepared = null ;
68+ $ new ->ignoreCase = $ flag ;
69+
70+ return $ new ;
71+ }
72+
73+ /**
74+ * Returns whether the pattern contains a dynamic part i.e.
75+ * has unescaped "*", "{", "?", or "[" character.
76+ *
77+ * @param string $pattern The pattern to check.
78+ *
79+ * @return bool Whether the pattern contains a dynamic part.
80+ */
81+ public static function isDynamic (string $ pattern ): bool
82+ {
83+ $ pattern = preg_replace ('/ \\\\./ ' , '' , $ pattern );
84+ return preg_match ('/[*{?\[]/ ' , $ pattern ) === 1 ;
85+ }
86+
87+ /**
88+ * Escapes pattern characters in a string.
89+ *
90+ * @param string $string Source string.
91+ *
92+ * @return string String with pattern characters escaped.
93+ */
94+ public static function quote (string $ string ): string
95+ {
96+ return preg_replace ('#([ \\\\?* \\[ \\]])# ' , '\\\\$1 ' , $ string );
97+ }
98+
99+ /**
100+ * @return non-empty-string
101+ */
102+ private function getPatternPrepared (): string
103+ {
104+ if ($ this ->patternPrepared !== null ) {
105+ return $ this ->patternPrepared ;
106+ }
54107
55108 $ replacements = [
56109 '\*\* ' => '.* ' ,
@@ -81,49 +134,15 @@ public function match(string $string): bool
81134 '\- ' => '- ' ,
82135 ];
83136
84- $ pattern = strtr (preg_quote ($ pattern , '# ' ), $ replacements );
137+ $ pattern = strtr (preg_quote ($ this -> pattern , '# ' ), $ replacements );
85138 $ pattern = '#^ ' . $ pattern . '$#us ' ;
86139
87140 if ($ this ->ignoreCase ) {
88141 $ pattern .= 'i ' ;
89142 }
90143
91- return preg_match ($ pattern , $ string ) === 1 ;
92- }
93-
94- /**
95- * Make pattern case insensitive.
96- */
97- public function ignoreCase (bool $ flag = true ): self
98- {
99- $ new = clone $ this ;
100- $ new ->ignoreCase = $ flag ;
101- return $ new ;
102- }
103-
104- /**
105- * Returns whether the pattern contains a dynamic part i.e.
106- * has unescaped "*", "{", "?", or "[" character.
107- *
108- * @param string $pattern The pattern to check.
109- *
110- * @return bool Whether the pattern contains a dynamic part.
111- */
112- public static function isDynamic (string $ pattern ): bool
113- {
114- $ pattern = preg_replace ('/ \\\\./ ' , '' , $ pattern );
115- return preg_match ('/[*{?\[]/ ' , $ pattern ) === 1 ;
116- }
144+ $ this ->patternPrepared = $ pattern ;
117145
118- /**
119- * Escapes pattern characters in a string.
120- *
121- * @param string $string Source string.
122- *
123- * @return string String with pattern characters escaped.
124- */
125- public static function quote (string $ string ): string
126- {
127- return preg_replace ('#([ \\\\?* \\[ \\]])# ' , '\\\\$1 ' , $ string );
146+ return $ this ->patternPrepared ;
128147 }
129148}
0 commit comments