7
7
use Doctrine \DBAL \SQL \Parser \Visitor ;
8
8
9
9
use function array_merge ;
10
- use function assert ;
11
- use function current ;
12
10
use function implode ;
13
- use function key ;
14
- use function next ;
15
11
use function preg_last_error ;
16
12
use function preg_match ;
17
- use function reset ;
18
13
use function sprintf ;
19
14
use function strlen ;
20
15
@@ -45,6 +40,7 @@ final class Parser
45
40
private const OTHER = '[^ ' . self ::SPECIAL_CHARS . ']+ ' ;
46
41
47
42
private string $ sqlPattern ;
43
+ private string $ tokenPattern ;
48
44
49
45
public function __construct (bool $ mySQLStringEscaping )
50
46
{
@@ -69,7 +65,12 @@ public function __construct(bool $mySQLStringEscaping)
69
65
self ::OTHER ,
70
66
]);
71
67
72
- $ this ->sqlPattern = sprintf ('(%s) ' , implode ('| ' , $ patterns ));
68
+ $ this ->sqlPattern = sprintf ('(%s) ' , implode ('| ' , $ patterns ));
69
+ $ this ->tokenPattern = '~ \\G '
70
+ . '(?P<named> ' . self ::NAMED_PARAMETER . ') '
71
+ . '|(?P<positional> ' . self ::POSITIONAL_PARAMETER . ') '
72
+ . '|(?P<other> ' . $ this ->sqlPattern . '| ' . self ::SPECIAL . ') '
73
+ . '~s ' ;
73
74
}
74
75
75
76
/**
@@ -79,40 +80,26 @@ public function __construct(bool $mySQLStringEscaping)
79
80
*/
80
81
public function parse (string $ sql , Visitor $ visitor ): void
81
82
{
82
- /** @var array<string,callable> $patterns */
83
- $ patterns = [
84
- self ::NAMED_PARAMETER => static function (string $ sql ) use ($ visitor ): void {
85
- $ visitor ->acceptNamedParameter ($ sql );
86
- },
87
- self ::POSITIONAL_PARAMETER => static function (string $ sql ) use ($ visitor ): void {
88
- $ visitor ->acceptPositionalParameter ($ sql );
89
- },
90
- $ this ->sqlPattern => static function (string $ sql ) use ($ visitor ): void {
91
- $ visitor ->acceptOther ($ sql );
92
- },
93
- self ::SPECIAL => static function (string $ sql ) use ($ visitor ): void {
94
- $ visitor ->acceptOther ($ sql );
95
- },
96
- ];
97
-
98
83
$ offset = 0 ;
99
-
100
- while (($ handler = current ($ patterns )) !== false ) {
101
- if (preg_match ('~\G ' . key ($ patterns ) . '~s ' , $ sql , $ matches , 0 , $ offset ) === 1 ) {
102
- $ handler ($ matches [0 ]);
103
- reset ($ patterns );
104
-
105
- $ offset += strlen ($ matches [0 ]);
84
+ $ length = strlen ($ sql );
85
+ while ($ offset < $ length ) {
86
+ if (preg_match ($ this ->tokenPattern , $ sql , $ matches , 0 , $ offset ) === 1 ) {
87
+ $ match = $ matches [0 ];
88
+ if ($ matches ['named ' ] !== '' ) {
89
+ $ visitor ->acceptNamedParameter ($ match );
90
+ } elseif ($ matches ['positional ' ] !== '' ) {
91
+ $ visitor ->acceptPositionalParameter ($ match );
92
+ } else {
93
+ $ visitor ->acceptOther ($ match );
94
+ }
95
+
96
+ $ offset += strlen ($ match );
106
97
} elseif (preg_last_error () !== PREG_NO_ERROR ) {
107
98
// @codeCoverageIgnoreStart
108
99
throw RegularExpressionError::new ();
109
100
// @codeCoverageIgnoreEnd
110
- } else {
111
- next ($ patterns );
112
101
}
113
102
}
114
-
115
- assert ($ offset === strlen ($ sql ));
116
103
}
117
104
118
105
private function getMySQLStringLiteralPattern (string $ delimiter ): string
0 commit comments