1<?php declare(strict_types=1); 2 3namespace PhpParser\Lexer\TokenEmulator; 4 5abstract 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 mixed[]|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