class SelfMemberReferenceSniff
Hierarchy
- class \PHP_CodeSniffer\Sniffs\AbstractScopeSniff implements \PHP_CodeSniffer\Sniffs\Sniff
- class \PHP_CodeSniffer\Standards\Squiz\Sniffs\Classes\SelfMemberReferenceSniff extends \PHP_CodeSniffer\Sniffs\AbstractScopeSniff
Expanded class hierarchy of SelfMemberReferenceSniff
File
-
vendor/
squizlabs/ php_codesniffer/ src/ Standards/ Squiz/ Sniffs/ Classes/ SelfMemberReferenceSniff.php, line 21
Namespace
PHP_CodeSniffer\Standards\Squiz\Sniffs\ClassesView source
class SelfMemberReferenceSniff extends AbstractScopeSniff {
/**
* Constructs a Squiz_Sniffs_Classes_SelfMemberReferenceSniff.
*/
public function __construct() {
parent::__construct([
T_CLASS,
], [
T_DOUBLE_COLON,
]);
}
//end __construct()
/**
* Processes the function tokens within the class.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found.
* @param int $stackPtr The position where the token was found.
* @param int $currScope The current scope opener token.
*
* @return void
*/
protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScope) {
$tokens = $phpcsFile->getTokens();
// Determine if this is a double colon which needs to be examined.
$conditions = $tokens[$stackPtr]['conditions'];
$conditions = array_reverse($conditions, true);
foreach ($conditions as $conditionToken => $tokenCode) {
if ($tokenCode === T_CLASS || $tokenCode === T_ANON_CLASS || $tokenCode === T_CLOSURE) {
break;
}
}
if ($conditionToken !== $currScope) {
return;
}
$calledClassName = $phpcsFile->findPrevious(Tokens::$emptyTokens, $stackPtr - 1, null, true);
if ($calledClassName === false) {
// Parse error.
return;
}
if ($tokens[$calledClassName]['code'] === T_SELF) {
if ($tokens[$calledClassName]['content'] !== 'self') {
$error = 'Must use "self::" for local static member reference; found "%s::"';
$data = [
$tokens[$calledClassName]['content'],
];
$fix = $phpcsFile->addFixableError($error, $calledClassName, 'IncorrectCase', $data);
if ($fix === true) {
$phpcsFile->fixer
->replaceToken($calledClassName, 'self');
}
return;
}
}
else {
if ($tokens[$calledClassName]['code'] === T_STRING) {
// If the class is called with a namespace prefix, build fully qualified
// namespace calls for both current scope class and requested class.
$prevNonEmpty = $phpcsFile->findPrevious(Tokens::$emptyTokens, $calledClassName - 1, null, true);
if ($prevNonEmpty !== false && $tokens[$prevNonEmpty]['code'] === T_NS_SEPARATOR) {
$declarationName = $this->getDeclarationNameWithNamespace($tokens, $calledClassName);
$declarationName = ltrim($declarationName, '\\');
$fullQualifiedClassName = $this->getNamespaceOfScope($phpcsFile, $currScope);
if ($fullQualifiedClassName === '\\') {
$fullQualifiedClassName = '';
}
else {
$fullQualifiedClassName .= '\\';
}
$fullQualifiedClassName .= $phpcsFile->getDeclarationName($currScope);
}
else {
$declarationName = $phpcsFile->getDeclarationName($currScope);
$fullQualifiedClassName = $tokens[$calledClassName]['content'];
}
if ($declarationName === $fullQualifiedClassName) {
// Class name is the same as the current class, which is not allowed.
$error = 'Must use "self::" for local static member reference';
$fix = $phpcsFile->addFixableError($error, $calledClassName, 'NotUsed');
if ($fix === true) {
$phpcsFile->fixer
->beginChangeset();
$currentPointer = $stackPtr - 1;
while ($tokens[$currentPointer]['code'] === T_NS_SEPARATOR || $tokens[$currentPointer]['code'] === T_STRING || isset(Tokens::$emptyTokens[$tokens[$currentPointer]['code']]) === true) {
if (isset(Tokens::$emptyTokens[$tokens[$currentPointer]['code']]) === true) {
--$currentPointer;
continue;
}
$phpcsFile->fixer
->replaceToken($currentPointer, '');
--$currentPointer;
}
$phpcsFile->fixer
->replaceToken($stackPtr, 'self::');
$phpcsFile->fixer
->endChangeset();
// Fix potential whitespace issues in the next loop.
return;
}
//end if
}
//end if
}
}
//end if
if ($tokens[$stackPtr - 1]['code'] === T_WHITESPACE) {
$found = $tokens[$stackPtr - 1]['length'];
$error = 'Expected 0 spaces before double colon; %s found';
$data = [
$found,
];
$fix = $phpcsFile->addFixableError($error, $stackPtr - 1, 'SpaceBefore', $data);
if ($fix === true) {
$phpcsFile->fixer
->beginChangeset();
for ($i = $stackPtr - 1; $tokens[$i]['code'] === T_WHITESPACE; $i--) {
$phpcsFile->fixer
->replaceToken($i, '');
}
$phpcsFile->fixer
->endChangeset();
}
}
if ($tokens[$stackPtr + 1]['code'] === T_WHITESPACE) {
$found = $tokens[$stackPtr + 1]['length'];
$error = 'Expected 0 spaces after double colon; %s found';
$data = [
$found,
];
$fix = $phpcsFile->addFixableError($error, $stackPtr - 1, 'SpaceAfter', $data);
if ($fix === true) {
$phpcsFile->fixer
->beginChangeset();
for ($i = $stackPtr + 1; $tokens[$i]['code'] === T_WHITESPACE; $i++) {
$phpcsFile->fixer
->replaceToken($i, '');
}
$phpcsFile->fixer
->endChangeset();
}
}
}
//end processTokenWithinScope()
/**
* Processes a token that is found within the scope that this test is
* listening to.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found.
* @param int $stackPtr The position in the stack where this
* token was found.
*
* @return void
*/
protected function processTokenOutsideScope(File $phpcsFile, $stackPtr) {
}
//end processTokenOutsideScope()
/**
* Returns the declaration names for classes/interfaces/functions with a namespace.
*
* @param array $tokens Token stack for this file.
* @param int $stackPtr The position where the namespace building will start.
*
* @return string
*/
protected function getDeclarationNameWithNamespace(array $tokens, $stackPtr) {
$nameParts = [];
$currentPointer = $stackPtr;
while ($tokens[$currentPointer]['code'] === T_NS_SEPARATOR || $tokens[$currentPointer]['code'] === T_STRING || isset(Tokens::$emptyTokens[$tokens[$currentPointer]['code']]) === true) {
if (isset(Tokens::$emptyTokens[$tokens[$currentPointer]['code']]) === true) {
--$currentPointer;
continue;
}
$nameParts[] = $tokens[$currentPointer]['content'];
--$currentPointer;
}
$nameParts = array_reverse($nameParts);
return implode('', $nameParts);
}
//end getDeclarationNameWithNamespace()
/**
* Returns the namespace declaration of a file.
*
* @param \PHP_CodeSniffer\Files\File $phpcsFile The file where this token was found.
* @param int $stackPtr The position where the search for the
* namespace declaration will start.
*
* @return string
*/
protected function getNamespaceOfScope(File $phpcsFile, $stackPtr) {
$namespace = '\\';
$tokens = $phpcsFile->getTokens();
while (($namespaceDeclaration = $phpcsFile->findPrevious(T_NAMESPACE, $stackPtr)) !== false) {
$nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, $namespaceDeclaration + 1, null, true);
if ($tokens[$nextNonEmpty]['code'] === T_NS_SEPARATOR) {
// Namespace operator. Ignore.
$stackPtr = $namespaceDeclaration - 1;
continue;
}
$endOfNamespaceDeclaration = $phpcsFile->findNext([
T_SEMICOLON,
T_OPEN_CURLY_BRACKET,
T_CLOSE_TAG,
], $namespaceDeclaration);
$namespace = $this->getDeclarationNameWithNamespace($phpcsFile->getTokens(), $endOfNamespaceDeclaration - 1);
break;
}
return $namespace;
}
//end getNamespaceOfScope()
}
Members
Title Sort descending | Modifiers | Object type | Summary | Overriden Title |
---|---|---|---|---|
AbstractScopeSniff::$listenOutside | private | property | True if this test should fire on tokens outside of the scope. | |
AbstractScopeSniff::$scopeTokens | private | property | The type of scope opener tokens that this test wishes to listen to. | |
AbstractScopeSniff::$tokens | private | property | The token types that this test wishes to listen to within the scope. | |
AbstractScopeSniff::process | final public | function | Processes the tokens that this test is listening for. | Overrides Sniff::process |
AbstractScopeSniff::register | final public | function | The method that is called to register the tokens this test wishes to listen to. |
Overrides Sniff::register |
SelfMemberReferenceSniff::getDeclarationNameWithNamespace | protected | function | Returns the declaration names for classes/interfaces/functions with a namespace. | |
SelfMemberReferenceSniff::getNamespaceOfScope | protected | function | Returns the namespace declaration of a file. | |
SelfMemberReferenceSniff::processTokenOutsideScope | protected | function | Processes a token that is found within the scope that this test is listening to. |
Overrides AbstractScopeSniff::processTokenOutsideScope |
SelfMemberReferenceSniff::processTokenWithinScope | protected | function | Processes the function tokens within the class. | Overrides AbstractScopeSniff::processTokenWithinScope |
SelfMemberReferenceSniff::__construct | public | function | Constructs a Squiz_Sniffs_Classes_SelfMemberReferenceSniff. | Overrides AbstractScopeSniff::__construct |