1: <?php declare(strict_types=1);
2:
3: namespace PhpParser\Lexer\TokenEmulator;
4:
5: abstract class KeywordEmulator extends TokenEmulator
6: {
7: abstract function getKeywordString(): string;
8: abstract function getKeywordToken(): int;
9:
10: public function isEmulationNeeded(string $code): bool
11: {
12: return strpos(strtolower($code), $this->getKeywordString()) !== false;
13: }
14:
15: protected function isKeywordContext(array $tokens, int $pos): bool
16: {
17: $previousNonSpaceToken = $this->getPreviousNonSpaceToken($tokens, $pos);
18: return $previousNonSpaceToken === null || $previousNonSpaceToken[0] !== \T_OBJECT_OPERATOR;
19: }
20:
21: public function emulate(string $code, array $tokens): array
22: {
23: $keywordString = $this->getKeywordString();
24: foreach ($tokens as $i => $token) {
25: if ($token[0] === T_STRING && strtolower($token[1]) === $keywordString
26: && $this->isKeywordContext($tokens, $i)) {
27: $tokens[$i][0] = $this->getKeywordToken();
28: }
29: }
30:
31: return $tokens;
32: }
33:
34: /**
35: * @param mixed[] $tokens
36: * @return array|string|null
37: */
38: private function getPreviousNonSpaceToken(array $tokens, int $start)
39: {
40: for ($i = $start - 1; $i >= 0; --$i) {
41: if ($tokens[$i][0] === T_WHITESPACE) {
42: continue;
43: }
44:
45: return $tokens[$i];
46: }
47:
48: return null;
49: }
50:
51: public function reverseEmulate(string $code, array $tokens): array
52: {
53: $keywordToken = $this->getKeywordToken();
54: foreach ($tokens as $i => $token) {
55: if ($token[0] === $keywordToken) {
56: $tokens[$i][0] = \T_STRING;
57: }
58: }
59:
60: return $tokens;
61: }
62: }
63: