99use Doctrine \DBAL \SQL \Parser \Visitor ;
1010
1111use function array_merge ;
12- use function assert ;
13- use function current ;
1412use function implode ;
15- use function key ;
16- use function next ;
1713use function preg_last_error ;
1814use function preg_match ;
19- use function reset ;
2015use function sprintf ;
2116use function strlen ;
2217
@@ -47,6 +42,7 @@ final class Parser
4742 private const OTHER = '[^ ' . self ::SPECIAL_CHARS . ']+ ' ;
4843
4944 private readonly string $ sqlPattern ;
45+ private readonly string $ tokenPattern ;
5046
5147 public function __construct (bool $ mySQLStringEscaping )
5248 {
@@ -71,7 +67,12 @@ public function __construct(bool $mySQLStringEscaping)
7167 self ::OTHER ,
7268 ]);
7369
74- $ this ->sqlPattern = sprintf ('(%s) ' , implode ('| ' , $ patterns ));
70+ $ this ->sqlPattern = sprintf ('(%s) ' , implode ('| ' , $ patterns ));
71+ $ this ->tokenPattern = '~ \\G '
72+ . '(?P<named> ' . self ::NAMED_PARAMETER . ') '
73+ . '|(?P<positional> ' . self ::POSITIONAL_PARAMETER . ') '
74+ . '|(?P<other> ' . $ this ->sqlPattern . '| ' . self ::SPECIAL . ') '
75+ . '~s ' ;
7576 }
7677
7778 /**
@@ -81,40 +82,26 @@ public function __construct(bool $mySQLStringEscaping)
8182 */
8283 public function parse (string $ sql , Visitor $ visitor ): void
8384 {
84- /** @var array<string,callable> $patterns */
85- $ patterns = [
86- self ::NAMED_PARAMETER => static function (string $ sql ) use ($ visitor ): void {
87- $ visitor ->acceptNamedParameter ($ sql );
88- },
89- self ::POSITIONAL_PARAMETER => static function (string $ sql ) use ($ visitor ): void {
90- $ visitor ->acceptPositionalParameter ($ sql );
91- },
92- $ this ->sqlPattern => static function (string $ sql ) use ($ visitor ): void {
93- $ visitor ->acceptOther ($ sql );
94- },
95- self ::SPECIAL => static function (string $ sql ) use ($ visitor ): void {
96- $ visitor ->acceptOther ($ sql );
97- },
98- ];
99-
10085 $ offset = 0 ;
101-
102- while (($ handler = current ($ patterns )) !== false ) {
103- if (preg_match ('~\G ' . key ($ patterns ) . '~s ' , $ sql , $ matches , 0 , $ offset ) === 1 ) {
104- $ handler ($ matches [0 ]);
105- reset ($ patterns );
106-
107- $ offset += strlen ($ matches [0 ]);
86+ $ length = strlen ($ sql );
87+ while ($ offset < $ length ) {
88+ if (preg_match ($ this ->tokenPattern , $ sql , $ matches , 0 , $ offset ) === 1 ) {
89+ $ match = $ matches [0 ];
90+ if ($ matches ['named ' ] !== '' ) {
91+ $ visitor ->acceptNamedParameter ($ match );
92+ } elseif ($ matches ['positional ' ] !== '' ) {
93+ $ visitor ->acceptPositionalParameter ($ match );
94+ } else {
95+ $ visitor ->acceptOther ($ match );
96+ }
97+
98+ $ offset += strlen ($ match );
10899 } elseif (preg_last_error () !== PREG_NO_ERROR ) {
109100 // @codeCoverageIgnoreStart
110101 throw RegularExpressionError::new ();
111102 // @codeCoverageIgnoreEnd
112- } else {
113- next ($ patterns );
114103 }
115104 }
116-
117- assert ($ offset === strlen ($ sql ));
118105 }
119106
120107 private function getMySQLStringLiteralPattern (string $ delimiter ): string
0 commit comments