tokens = token_get_all($fileContents); } /** * Moves head to the beginning and cleans the internal bookmarks. */ public function reset() { $this->head = 0; $this->headBookmarks = []; } public function getHead() { return $this->head; } /** * Updates the head position. * @return boolean Returns true if the head was successfully updated. Returns false otherwise. */ public function setHead($head) { if ($head < 0) { return false; } if ($head > (count($this->tokens) - 1)) { return false; } $this->head = $head; return true; } /** * Bookmarks the head position in the internal bookmark stack. */ public function bookmarkHead() { array_push($this->headBookmarks, $this->head); } /** * Restores the head position from the last stored bookmark. */ public function restoreBookmark() { $head = array_pop($this->headBookmarks); if ($head === null) { throw new SystemException("Can't restore PHP token stream bookmark - the bookmark doesn't exist"); } return $this->setHead($head); } /** * Discards the last stored bookmark without changing the head position. */ public function discardBookmark() { $head = array_pop($this->headBookmarks); if ($head === null) { throw new SystemException("Can't discard PHP token stream bookmark - the bookmark doesn't exist"); } } /** * Returns the current token and doesn't move the head. */ public function getCurrent() { return $this->tokens[$this->head]; } /** * Returns the current token's text and doesn't move the head. */ public function getCurrentText() { $token = $this->getCurrent(); if (!is_array($token)) { return $token; } return $token[1]; } /** * Returns the current token's code and doesn't move the head. */ public function getCurrentCode() { $token = $this->getCurrent(); if (!is_array($token)) { return null; } return $token[0]; } /** * Returns the next token and moves the head forward. */ public function getNext() { $nextIndex = $this->head + 1; if (!array_key_exists($nextIndex, $this->tokens)) { return null; } $this->head = $nextIndex; return $this->tokens[$nextIndex]; } /** * Reads the next token, updates the head and and returns the token if it has the expected code. * @param integer $expectedCode Specifies the code to expect. * @return mixed Returns the token or null if the token code was not expected. */ public function getNextExpected($expectedCode) { $token = $this->getNext(); if ($this->getCurrentCode() != $expectedCode) { return null; } return $token; } /** * Reads expected tokens, until the termination token is found. * If any unexpected token is found before the termination token, returns null. * If the method succeeds, the head is positioned on the termination token. * @param array $expectedCodesOrValues Specifies the expected codes or token values. * @param integer|string|array $terminationToken Specifies the termination token text or code. * The termination tokens could be specified as array. * @return string|null Returns the tokens text or null */ public function getNextExpectedTerminated($expectedCodesOrValues, $terminationToken) { $buffer = null; if (!is_array($terminationToken)) { $terminationToken = [$terminationToken]; } while (($nextToken = $this->getNext()) !== null) { $code = $this->getCurrentCode(); $text = $this->getCurrentText(); if (in_array($code, $expectedCodesOrValues) || in_array($text, $expectedCodesOrValues)) { $buffer .= $text; continue; } if (in_array($code, $terminationToken)) { return $buffer; } if (in_array($text, $terminationToken)) { return $buffer; } // The token should be either expected or termination. // If something else is found, return null. return null; } return $buffer; } /** * Moves the head forward. * @return boolean Returns true if the head was successfully moved. * Returns false if the head can't be moved because it has reached the end of the steam. */ public function forward() { return $this->setHead($this->getHead()+1); } /** * Moves the head backward. * @return boolean Returns true if the head was successfully moved. * Returns false if the head can't be moved because it has reached the beginning of the steam. */ public function back() { return $this->setHead($this->getHead()-1); } /** * Returns the stream text from the head position to the next semicolon and updates the head. * If the method succeeds, the head is positioned on the semicolon. */ public function getTextToSemicolon() { $buffer = null; while (($nextToken = $this->getNext()) !== null) { if ($nextToken == ';') { return $buffer; } $buffer .= $this->getCurrentText(); } // The semicolon wasn't found. return null; } public function unquotePhpString($string) { if ((substr($string, 0, 1) === '\'' && substr($string, -1) === '\'') || (substr($string, 0, 1) === '"' && substr($string, -1) === '"')) { return substr($string, 1, -1); } return false; } }