File: //usr/local/wp/vendor/phpcsstandards/phpcsutils/PHPCSUtils/Utils/Constants.php
<?php
/**
* PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers.
*
* @package PHPCSUtils
* @copyright 2019-2020 PHPCSUtils Contributors
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
* @link https://github.com/PHPCSStandards/PHPCSUtils
*/
namespace PHPCSUtils\Utils;
use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Util\Tokens;
use PHPCSUtils\Exceptions\OutOfBoundsStackPtr;
use PHPCSUtils\Exceptions\TypeError;
use PHPCSUtils\Exceptions\UnexpectedTokenType;
use PHPCSUtils\Exceptions\ValueError;
use PHPCSUtils\Internal\Cache;
use PHPCSUtils\Tokens\Collections;
use PHPCSUtils\Utils\Scopes;
/**
* Utility functions for use when examining constants declared using the "const" keyword.
*
* @since 1.1.0
*/
final class Constants
{
/**
* Retrieve the visibility and implementation properties of an OO constant.
*
* @since 1.1.0
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
* @param int $stackPtr The position in the stack of the `T_CONST` token
* to acquire the properties for.
*
* @return array<string, string|int|bool> Array with information about the constant declaration.
* The format of the return value is:
* ```php
* array(
* 'scope' => string, // Public, private, or protected.
* 'scope_token' => integer|false, // The stack pointer to the scope keyword or
* // FALSE if the scope was not explicitly specified.
* 'is_final' => boolean, // TRUE if the final keyword was found.
* 'final_token' => integer|false, // The stack pointer to the final keyword
* // or FALSE if the const is not declared final.
* 'type' => string, // The type of the const (empty if no type specified).
* 'type_token' => integer|false, // The stack pointer to the start of the type
* // or FALSE if there is no type.
* 'type_end_token' => integer|false, // The stack pointer to the end of the type
* // or FALSE if there is no type.
* 'nullable_type' => boolean, // TRUE if the type is preceded by the
* // nullability operator.
* 'name_token' => integer, // The stack pointer to the constant name.
* // Note: for group declarations this points to the
* // name of the first constant.
* 'equal_token' => integer, // The stack pointer to the equal sign.
* // Note: for group declarations this points to the
* // equal sign of the first constant.
* );
* ```
*
* @throws \PHPCSUtils\Exceptions\TypeError If the $stackPtr parameter is not an integer.
* @throws \PHPCSUtils\Exceptions\OutOfBoundsStackPtr If the token passed does not exist in the $phpcsFile.
* @throws \PHPCSUtils\Exceptions\UnexpectedTokenType If the token passed is not a `T_CONST` token.
* @throws \PHPCSUtils\Exceptions\ValueError If the specified position is not an OO constant.
*/
public static function getProperties(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
if (\is_int($stackPtr) === false) {
throw TypeError::create(2, '$stackPtr', 'integer', $stackPtr);
}
if (isset($tokens[$stackPtr]) === false) {
throw OutOfBoundsStackPtr::create(2, '$stackPtr', $stackPtr);
}
if ($tokens[$stackPtr]['code'] !== \T_CONST) {
throw UnexpectedTokenType::create(2, '$stackPtr', 'T_CONST', $tokens[$stackPtr]['type']);
}
if (Scopes::isOOConstant($phpcsFile, $stackPtr) === false) {
throw ValueError::create(2, '$stackPtr', 'must be the pointer to an OO constant');
}
if (Cache::isCached($phpcsFile, __METHOD__, $stackPtr) === true) {
return Cache::get($phpcsFile, __METHOD__, $stackPtr);
}
$find = [\T_EQUAL, \T_SEMICOLON, \T_OPEN_CURLY_BRACKET, \T_CLOSE_CURLY_BRACKET, \T_CLOSE_TAG];
$assignmentPtr = $phpcsFile->findNext($find, ($stackPtr + 1));
if ($assignmentPtr === false || $tokens[$assignmentPtr]['code'] !== \T_EQUAL) {
// Probably a parse error. Don't cache the result.
throw ValueError::create(2, '$stackPtr', 'must be the pointer to an OO constant');
}
$namePtr = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($assignmentPtr - 1), ($stackPtr + 1), true);
$returnValue = [
'scope' => 'public',
'scope_token' => false,
'is_final' => false,
'final_token' => false,
'type' => '',
'type_token' => false,
'type_end_token' => false,
'nullable_type' => false,
'name_token' => $namePtr,
'equal_token' => $assignmentPtr,
];
for ($i = ($stackPtr - 1);; $i--) {
// Skip over potentially large docblocks.
if ($tokens[$i]['code'] === \T_DOC_COMMENT_CLOSE_TAG
&& isset($tokens[$i]['comment_opener'])
) {
$i = $tokens[$i]['comment_opener'];
continue;
}
if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) {
continue;
}
switch ($tokens[$i]['code']) {
case \T_PUBLIC:
$returnValue['scope'] = 'public';
$returnValue['scope_token'] = $i;
break;
case \T_PROTECTED:
$returnValue['scope'] = 'protected';
$returnValue['scope_token'] = $i;
break;
case \T_PRIVATE:
$returnValue['scope'] = 'private';
$returnValue['scope_token'] = $i;
break;
case \T_FINAL:
$returnValue['is_final'] = true;
$returnValue['final_token'] = $i;
break;
default:
// Any other token means that the start of the statement has been reached.
break 2;
}
}
$type = '';
$typeToken = false;
$typeEndToken = false;
$constantTypeTokens = Collections::constantTypeTokens();
// Now, let's check for a type.
for ($i = ($stackPtr + 1); $i < $namePtr; $i++) {
if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) {
continue;
}
if ($tokens[$i]['code'] === \T_NULLABLE) {
$returnValue['nullable_type'] = true;
continue;
}
if (isset($constantTypeTokens[$tokens[$i]['code']]) === true) {
$typeEndToken = $i;
if ($typeToken === false) {
$typeToken = $i;
}
$type .= $tokens[$i]['content'];
}
}
if ($type !== '' && $returnValue['nullable_type'] === true) {
$type = '?' . $type;
}
$returnValue['type'] = $type;
$returnValue['type_token'] = $typeToken;
$returnValue['type_end_token'] = $typeEndToken;
Cache::set($phpcsFile, __METHOD__, $stackPtr, $returnValue);
return $returnValue;
}
}