基础代码
This commit is contained in:
+90
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
/**
|
||||
* PHPCompatibility, an external standard for PHP_CodeSniffer.
|
||||
*
|
||||
* @package PHPCompatibility
|
||||
* @copyright 2012-2019 PHPCompatibility Contributors
|
||||
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
|
||||
* @link https://github.com/PHPCompatibility/PHPCompatibility
|
||||
*/
|
||||
|
||||
namespace PHPCompatibility\Sniffs\Classes;
|
||||
|
||||
use PHPCompatibility\Sniff;
|
||||
use PHP_CodeSniffer_File as File;
|
||||
|
||||
/**
|
||||
* Abstract private methods are not allowed since PHP 5.1.
|
||||
*
|
||||
* Abstract private methods were supported between PHP 5.0.0 and PHP 5.0.4, but
|
||||
* were then disallowed on the grounds that the behaviours of `private` and `abstract`
|
||||
* are mutually exclusive.
|
||||
*
|
||||
* PHP version 5.1
|
||||
*
|
||||
* @link https://www.php.net/manual/en/migration51.oop.php#migration51.oop-methods
|
||||
*
|
||||
* @since 9.2.0
|
||||
*/
|
||||
class ForbiddenAbstractPrivateMethodsSniff extends Sniff
|
||||
{
|
||||
|
||||
/**
|
||||
* Valid scopes to check for abstract private methods.
|
||||
*
|
||||
* @since 9.2.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $ooScopeTokens = array(
|
||||
'T_CLASS' => true,
|
||||
'T_TRAIT' => true,
|
||||
'T_ANON_CLASS' => true,
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns an array of tokens this test wants to listen for.
|
||||
*
|
||||
* @since 9.2.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
return array(\T_FUNCTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes this test, when one of its tokens is encountered.
|
||||
*
|
||||
* @since 9.2.0
|
||||
*
|
||||
* @param \PHP_CodeSniffer_File $phpcsFile The file being scanned.
|
||||
* @param int $stackPtr The position of the current token
|
||||
* in the stack passed in $tokens.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function process(File $phpcsFile, $stackPtr)
|
||||
{
|
||||
if ($this->supportsAbove('5.1') === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->validDirectScope($phpcsFile, $stackPtr, $this->ooScopeTokens) === false) {
|
||||
// Function, not method.
|
||||
return;
|
||||
}
|
||||
|
||||
$properties = $phpcsFile->getMethodProperties($stackPtr);
|
||||
if ($properties['scope'] !== 'private' || $properties['is_abstract'] !== true) {
|
||||
return;
|
||||
}
|
||||
|
||||
$phpcsFile->addError(
|
||||
'Abstract methods cannot be declared as private since PHP 5.1',
|
||||
$stackPtr,
|
||||
'Found'
|
||||
);
|
||||
}
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
/**
|
||||
* PHPCompatibility, an external standard for PHP_CodeSniffer.
|
||||
*
|
||||
* @package PHPCompatibility
|
||||
* @copyright 2012-2019 PHPCompatibility Contributors
|
||||
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
|
||||
* @link https://github.com/PHPCompatibility/PHPCompatibility
|
||||
*/
|
||||
|
||||
namespace PHPCompatibility\Sniffs\Classes;
|
||||
|
||||
use PHPCompatibility\Sniff;
|
||||
use PHP_CodeSniffer_File as File;
|
||||
use PHP_CodeSniffer_Tokens as Tokens;
|
||||
|
||||
/**
|
||||
* Anonymous classes are supported since PHP 7.0.
|
||||
*
|
||||
* PHP version 7.0
|
||||
*
|
||||
* @link https://www.php.net/manual/en/language.oop5.anonymous.php
|
||||
* @link https://wiki.php.net/rfc/anonymous_classes
|
||||
*
|
||||
* @since 7.0.0
|
||||
*/
|
||||
class NewAnonymousClassesSniff extends Sniff
|
||||
{
|
||||
|
||||
/**
|
||||
* Tokens which in various PHP versions indicate the `class` keyword.
|
||||
*
|
||||
* The dedicated anonymous class token is added from the `register()`
|
||||
* method if the token is available.
|
||||
*
|
||||
* @since 7.1.2
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $indicators = array(
|
||||
\T_CLASS => \T_CLASS,
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns an array of tokens this test wants to listen for.
|
||||
*
|
||||
* @since 7.0.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
if (\defined('T_ANON_CLASS')) {
|
||||
$this->indicators[\T_ANON_CLASS] = \T_ANON_CLASS;
|
||||
}
|
||||
|
||||
return array(\T_NEW);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes this test, when one of its tokens is encountered.
|
||||
*
|
||||
* @since 7.0.0
|
||||
*
|
||||
* @param \PHP_CodeSniffer_File $phpcsFile The file being scanned.
|
||||
* @param int $stackPtr The position of the current token in the
|
||||
* stack passed in $tokens.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function process(File $phpcsFile, $stackPtr)
|
||||
{
|
||||
if ($this->supportsBelow('5.6') === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tokens = $phpcsFile->getTokens();
|
||||
$nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, $stackPtr + 1, null, true, null, true);
|
||||
if ($nextNonEmpty === false || isset($this->indicators[$tokens[$nextNonEmpty]['code']]) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Still here ? In that case, it is an anonymous class.
|
||||
$phpcsFile->addError(
|
||||
'Anonymous classes are not supported in PHP 5.6 or earlier',
|
||||
$stackPtr,
|
||||
'Found'
|
||||
);
|
||||
}
|
||||
}
|
||||
Vendored
+913
@@ -0,0 +1,913 @@
|
||||
<?php
|
||||
/**
|
||||
* PHPCompatibility, an external standard for PHP_CodeSniffer.
|
||||
*
|
||||
* @package PHPCompatibility
|
||||
* @copyright 2012-2019 PHPCompatibility Contributors
|
||||
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
|
||||
* @link https://github.com/PHPCompatibility/PHPCompatibility
|
||||
*/
|
||||
|
||||
namespace PHPCompatibility\Sniffs\Classes;
|
||||
|
||||
use PHPCompatibility\AbstractNewFeatureSniff;
|
||||
use PHP_CodeSniffer_File as File;
|
||||
|
||||
/**
|
||||
* Detect use of new PHP native classes.
|
||||
*
|
||||
* The sniff analyses the following constructs to find usage of new classes:
|
||||
* - Class instantiation using the `new` keyword.
|
||||
* - (Anonymous) Class declarations to detect new classes being extended by userland classes.
|
||||
* - Static use of class properties, constants or functions using the double colon.
|
||||
* - Function/closure declarations to detect new classes used as parameter type declarations.
|
||||
* - Function/closure declarations to detect new classes used as return type declarations.
|
||||
* - Try/catch statements to detect new exception classes being caught.
|
||||
*
|
||||
* PHP version All
|
||||
*
|
||||
* @since 5.5
|
||||
* @since 5.6 Now extends the base `Sniff` class.
|
||||
* @since 7.1.0 Now extends the `AbstractNewFeatureSniff` class.
|
||||
*/
|
||||
class NewClassesSniff extends AbstractNewFeatureSniff
|
||||
{
|
||||
|
||||
/**
|
||||
* A list of new classes, not present in older versions.
|
||||
*
|
||||
* The array lists : version number with false (not present) or true (present).
|
||||
* If's sufficient to list the first version where the class appears.
|
||||
*
|
||||
* @since 5.5
|
||||
*
|
||||
* @var array(string => array(string => bool))
|
||||
*/
|
||||
protected $newClasses = array(
|
||||
'ArrayObject' => array(
|
||||
'4.4' => false,
|
||||
'5.0' => true,
|
||||
),
|
||||
'ArrayIterator' => array(
|
||||
'4.4' => false,
|
||||
'5.0' => true,
|
||||
),
|
||||
'CachingIterator' => array(
|
||||
'4.4' => false,
|
||||
'5.0' => true,
|
||||
),
|
||||
'DirectoryIterator' => array(
|
||||
'4.4' => false,
|
||||
'5.0' => true,
|
||||
),
|
||||
'RecursiveDirectoryIterator' => array(
|
||||
'4.4' => false,
|
||||
'5.0' => true,
|
||||
),
|
||||
'RecursiveIteratorIterator' => array(
|
||||
'4.4' => false,
|
||||
'5.0' => true,
|
||||
),
|
||||
'php_user_filter' => array(
|
||||
'4.4' => false,
|
||||
'5.0' => true,
|
||||
),
|
||||
'tidy' => array(
|
||||
'4.4' => false,
|
||||
'5.0' => true,
|
||||
),
|
||||
|
||||
'SimpleXMLElement' => array(
|
||||
'5.0.0' => false,
|
||||
'5.0.1' => true,
|
||||
),
|
||||
'tidyNode' => array(
|
||||
'5.0.0' => false,
|
||||
'5.0.1' => true,
|
||||
),
|
||||
|
||||
'libXMLError' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'PDO' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'PDOStatement' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'AppendIterator' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'EmptyIterator' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'FilterIterator' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'InfiniteIterator' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'IteratorIterator' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'LimitIterator' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'NoRewindIterator' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'ParentIterator' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'RecursiveArrayIterator' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'RecursiveCachingIterator' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'RecursiveFilterIterator' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'SimpleXMLIterator' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'SplFileObject' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'XMLReader' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
|
||||
'SplFileInfo' => array(
|
||||
'5.1.1' => false,
|
||||
'5.1.2' => true,
|
||||
),
|
||||
'SplTempFileObject' => array(
|
||||
'5.1.1' => false,
|
||||
'5.1.2' => true,
|
||||
),
|
||||
'XMLWriter' => array(
|
||||
'5.1.1' => false,
|
||||
'5.1.2' => true,
|
||||
),
|
||||
|
||||
'DateTime' => array(
|
||||
'5.1' => false,
|
||||
'5.2' => true,
|
||||
),
|
||||
'DateTimeZone' => array(
|
||||
'5.1' => false,
|
||||
'5.2' => true,
|
||||
),
|
||||
'RegexIterator' => array(
|
||||
'5.1' => false,
|
||||
'5.2' => true,
|
||||
),
|
||||
'RecursiveRegexIterator' => array(
|
||||
'5.1' => false,
|
||||
'5.2' => true,
|
||||
),
|
||||
'ReflectionFunctionAbstract' => array(
|
||||
'5.1' => false,
|
||||
'5.2' => true,
|
||||
),
|
||||
'ZipArchive' => array(
|
||||
'5.1' => false,
|
||||
'5.2' => true,
|
||||
),
|
||||
|
||||
'Closure' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'DateInterval' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'DatePeriod' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'finfo' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'Collator' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'NumberFormatter' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'Locale' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'Normalizer' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'MessageFormatter' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'IntlDateFormatter' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'Phar' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'PharData' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'PharFileInfo' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'FilesystemIterator' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'GlobIterator' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'MultipleIterator' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'RecursiveTreeIterator' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'SplDoublyLinkedList' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'SplFixedArray' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'SplHeap' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'SplMaxHeap' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'SplMinHeap' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'SplObjectStorage' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'SplPriorityQueue' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'SplQueue' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
'SplStack' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
|
||||
'ResourceBundle' => array(
|
||||
'5.3.1' => false,
|
||||
'5.3.2' => true,
|
||||
),
|
||||
|
||||
'CallbackFilterIterator' => array(
|
||||
'5.3' => false,
|
||||
'5.4' => true,
|
||||
),
|
||||
'RecursiveCallbackFilterIterator' => array(
|
||||
'5.3' => false,
|
||||
'5.4' => true,
|
||||
),
|
||||
'ReflectionZendExtension' => array(
|
||||
'5.3' => false,
|
||||
'5.4' => true,
|
||||
),
|
||||
'SessionHandler' => array(
|
||||
'5.3' => false,
|
||||
'5.4' => true,
|
||||
),
|
||||
'SNMP' => array(
|
||||
'5.3' => false,
|
||||
'5.4' => true,
|
||||
),
|
||||
'Transliterator' => array(
|
||||
'5.3' => false,
|
||||
'5.4' => true,
|
||||
),
|
||||
'Spoofchecker' => array(
|
||||
'5.3' => false,
|
||||
'5.4' => true,
|
||||
),
|
||||
|
||||
'Generator' => array(
|
||||
'5.4' => false,
|
||||
'5.5' => true,
|
||||
),
|
||||
'CURLFile' => array(
|
||||
'5.4' => false,
|
||||
'5.5' => true,
|
||||
),
|
||||
'DateTimeImmutable' => array(
|
||||
'5.4' => false,
|
||||
'5.5' => true,
|
||||
),
|
||||
'IntlCalendar' => array(
|
||||
'5.4' => false,
|
||||
'5.5' => true,
|
||||
),
|
||||
'IntlGregorianCalendar' => array(
|
||||
'5.4' => false,
|
||||
'5.5' => true,
|
||||
),
|
||||
'IntlTimeZone' => array(
|
||||
'5.4' => false,
|
||||
'5.5' => true,
|
||||
),
|
||||
'IntlBreakIterator' => array(
|
||||
'5.4' => false,
|
||||
'5.5' => true,
|
||||
),
|
||||
'IntlRuleBasedBreakIterator' => array(
|
||||
'5.4' => false,
|
||||
'5.5' => true,
|
||||
),
|
||||
'IntlCodePointBreakIterator' => array(
|
||||
'5.4' => false,
|
||||
'5.5' => true,
|
||||
),
|
||||
'UConverter' => array(
|
||||
'5.4' => false,
|
||||
'5.5' => true,
|
||||
),
|
||||
|
||||
'GMP' => array(
|
||||
'5.5' => false,
|
||||
'5.6' => true,
|
||||
),
|
||||
|
||||
'IntlChar' => array(
|
||||
'5.6' => false,
|
||||
'7.0' => true,
|
||||
),
|
||||
'ReflectionType' => array(
|
||||
'5.6' => false,
|
||||
'7.0' => true,
|
||||
),
|
||||
'ReflectionGenerator' => array(
|
||||
'5.6' => false,
|
||||
'7.0' => true,
|
||||
),
|
||||
|
||||
'ReflectionClassConstant' => array(
|
||||
'7.0' => false,
|
||||
'7.1' => true,
|
||||
),
|
||||
|
||||
'FFI' => array(
|
||||
'7.3' => false,
|
||||
'7.4' => true,
|
||||
),
|
||||
'FFI\CData' => array(
|
||||
'7.3' => false,
|
||||
'7.4' => true,
|
||||
),
|
||||
'FFI\CType' => array(
|
||||
'7.3' => false,
|
||||
'7.4' => true,
|
||||
),
|
||||
'ReflectionReference' => array(
|
||||
'7.3' => false,
|
||||
'7.4' => true,
|
||||
),
|
||||
'WeakReference' => array(
|
||||
'7.3' => false,
|
||||
'7.4' => true,
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* A list of new Exception classes, not present in older versions.
|
||||
*
|
||||
* The array lists : version number with false (not present) or true (present).
|
||||
* If's sufficient to list the first version where the class appears.
|
||||
*
|
||||
* {@internal Classes listed here do not need to be added to the $newClasses
|
||||
* property as well.
|
||||
* This list is automatically added to the $newClasses property
|
||||
* in the `register()` method.}
|
||||
*
|
||||
* {@internal Helper to update this list: https://3v4l.org/MhlUp}
|
||||
*
|
||||
* @since 7.1.4
|
||||
*
|
||||
* @var array(string => array(string => bool))
|
||||
*/
|
||||
protected $newExceptions = array(
|
||||
'com_exception' => array(
|
||||
'4.4' => false,
|
||||
'5.0' => true,
|
||||
),
|
||||
'DOMException' => array(
|
||||
'4.4' => false,
|
||||
'5.0' => true,
|
||||
),
|
||||
'Exception' => array(
|
||||
// According to the docs introduced in PHP 5.1, but this appears to be.
|
||||
// an error. Class was introduced with try/catch keywords in PHP 5.0.
|
||||
'4.4' => false,
|
||||
'5.0' => true,
|
||||
),
|
||||
'ReflectionException' => array(
|
||||
'4.4' => false,
|
||||
'5.0' => true,
|
||||
),
|
||||
'SoapFault' => array(
|
||||
'4.4' => false,
|
||||
'5.0' => true,
|
||||
),
|
||||
'SQLiteException' => array(
|
||||
'4.4' => false,
|
||||
'5.0' => true,
|
||||
),
|
||||
|
||||
'ErrorException' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'BadFunctionCallException' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'BadMethodCallException' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'DomainException' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'InvalidArgumentException' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'LengthException' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'LogicException' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'mysqli_sql_exception' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'OutOfBoundsException' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'OutOfRangeException' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'OverflowException' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'PDOException' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'RangeException' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'RuntimeException' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'UnderflowException' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
'UnexpectedValueException' => array(
|
||||
'5.0' => false,
|
||||
'5.1' => true,
|
||||
),
|
||||
|
||||
'PharException' => array(
|
||||
'5.2' => false,
|
||||
'5.3' => true,
|
||||
),
|
||||
|
||||
'SNMPException' => array(
|
||||
'5.3' => false,
|
||||
'5.4' => true,
|
||||
),
|
||||
|
||||
'IntlException' => array(
|
||||
'5.4' => false,
|
||||
'5.5' => true,
|
||||
),
|
||||
|
||||
'Error' => array(
|
||||
'5.6' => false,
|
||||
'7.0' => true,
|
||||
),
|
||||
'ArithmeticError' => array(
|
||||
'5.6' => false,
|
||||
'7.0' => true,
|
||||
),
|
||||
'AssertionError' => array(
|
||||
'5.6' => false,
|
||||
'7.0' => true,
|
||||
),
|
||||
'DivisionByZeroError' => array(
|
||||
'5.6' => false,
|
||||
'7.0' => true,
|
||||
),
|
||||
'ParseError' => array(
|
||||
'5.6' => false,
|
||||
'7.0' => true,
|
||||
),
|
||||
'TypeError' => array(
|
||||
'5.6' => false,
|
||||
'7.0' => true,
|
||||
),
|
||||
'ClosedGeneratorException' => array(
|
||||
'5.6' => false,
|
||||
'7.0' => true,
|
||||
),
|
||||
'UI\Exception\InvalidArgumentException' => array(
|
||||
'5.6' => false,
|
||||
'7.0' => true,
|
||||
),
|
||||
'UI\Exception\RuntimeException' => array(
|
||||
'5.6' => false,
|
||||
'7.0' => true,
|
||||
),
|
||||
|
||||
'ArgumentCountError' => array(
|
||||
'7.0' => false,
|
||||
'7.1' => true,
|
||||
),
|
||||
|
||||
'SodiumException' => array(
|
||||
'7.1' => false,
|
||||
'7.2' => true,
|
||||
),
|
||||
|
||||
'CompileError' => array(
|
||||
'7.2' => false,
|
||||
'7.3' => true,
|
||||
),
|
||||
'JsonException' => array(
|
||||
'7.2' => false,
|
||||
'7.3' => true,
|
||||
),
|
||||
|
||||
'FFI\Exception' => array(
|
||||
'7.3' => false,
|
||||
'7.4' => true,
|
||||
),
|
||||
'FFI\ParserException' => array(
|
||||
'7.3' => false,
|
||||
'7.4' => true,
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of tokens this test wants to listen for.
|
||||
*
|
||||
* @since 5.5
|
||||
* @since 7.0.3 - Now also targets the `class` keyword to detect extended classes.
|
||||
* - Now also targets double colons to detect static class use.
|
||||
* @since 7.1.4 - Now also targets anonymous classes to detect extended classes.
|
||||
* - Now also targets functions/closures to detect new classes used
|
||||
* as parameter type declarations.
|
||||
* - Now also targets the `catch` control structure to detect new
|
||||
* exception classes being caught.
|
||||
* @since 8.2.0 Now also targets the `T_RETURN_TYPE` token to detect new classes used
|
||||
* as return type declarations.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
// Handle case-insensitivity of class names.
|
||||
$this->newClasses = $this->arrayKeysToLowercase($this->newClasses);
|
||||
$this->newExceptions = $this->arrayKeysToLowercase($this->newExceptions);
|
||||
|
||||
// Add the Exception classes to the Classes list.
|
||||
$this->newClasses = array_merge($this->newClasses, $this->newExceptions);
|
||||
|
||||
$targets = array(
|
||||
\T_NEW,
|
||||
\T_CLASS,
|
||||
\T_DOUBLE_COLON,
|
||||
\T_FUNCTION,
|
||||
\T_CLOSURE,
|
||||
\T_CATCH,
|
||||
);
|
||||
|
||||
if (\defined('T_ANON_CLASS')) {
|
||||
$targets[] = \T_ANON_CLASS;
|
||||
}
|
||||
|
||||
if (\defined('T_RETURN_TYPE')) {
|
||||
$targets[] = \T_RETURN_TYPE;
|
||||
}
|
||||
|
||||
return $targets;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes this test, when one of its tokens is encountered.
|
||||
*
|
||||
* @since 5.5
|
||||
*
|
||||
* @param \PHP_CodeSniffer_File $phpcsFile The file being scanned.
|
||||
* @param int $stackPtr The position of the current token in
|
||||
* the stack passed in $tokens.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function process(File $phpcsFile, $stackPtr)
|
||||
{
|
||||
$tokens = $phpcsFile->getTokens();
|
||||
|
||||
switch ($tokens[$stackPtr]['type']) {
|
||||
case 'T_FUNCTION':
|
||||
case 'T_CLOSURE':
|
||||
$this->processFunctionToken($phpcsFile, $stackPtr);
|
||||
|
||||
// Deal with older PHPCS version which don't recognize return type hints
|
||||
// as well as newer PHPCS versions (3.3.0+) where the tokenization has changed.
|
||||
$returnTypeHint = $this->getReturnTypeHintToken($phpcsFile, $stackPtr);
|
||||
if ($returnTypeHint !== false) {
|
||||
$this->processReturnTypeToken($phpcsFile, $returnTypeHint);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'T_CATCH':
|
||||
$this->processCatchToken($phpcsFile, $stackPtr);
|
||||
break;
|
||||
|
||||
case 'T_RETURN_TYPE':
|
||||
$this->processReturnTypeToken($phpcsFile, $stackPtr);
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->processSingularToken($phpcsFile, $stackPtr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes this test for when a token resulting in a singular class name is encountered.
|
||||
*
|
||||
* @since 7.1.4
|
||||
*
|
||||
* @param \PHP_CodeSniffer_File $phpcsFile The file being scanned.
|
||||
* @param int $stackPtr The position of the current token in
|
||||
* the stack passed in $tokens.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function processSingularToken(File $phpcsFile, $stackPtr)
|
||||
{
|
||||
$tokens = $phpcsFile->getTokens();
|
||||
$FQClassName = '';
|
||||
|
||||
if ($tokens[$stackPtr]['type'] === 'T_NEW') {
|
||||
$FQClassName = $this->getFQClassNameFromNewToken($phpcsFile, $stackPtr);
|
||||
|
||||
} elseif ($tokens[$stackPtr]['type'] === 'T_CLASS' || $tokens[$stackPtr]['type'] === 'T_ANON_CLASS') {
|
||||
$FQClassName = $this->getFQExtendedClassName($phpcsFile, $stackPtr);
|
||||
|
||||
} elseif ($tokens[$stackPtr]['type'] === 'T_DOUBLE_COLON') {
|
||||
$FQClassName = $this->getFQClassNameFromDoubleColonToken($phpcsFile, $stackPtr);
|
||||
}
|
||||
|
||||
if ($FQClassName === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$className = substr($FQClassName, 1); // Remove global namespace indicator.
|
||||
$classNameLc = strtolower($className);
|
||||
|
||||
if (isset($this->newClasses[$classNameLc]) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$itemInfo = array(
|
||||
'name' => $className,
|
||||
'nameLc' => $classNameLc,
|
||||
);
|
||||
$this->handleFeature($phpcsFile, $stackPtr, $itemInfo);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes this test for when a function token is encountered.
|
||||
*
|
||||
* - Detect new classes when used as a parameter type declaration.
|
||||
*
|
||||
* @since 7.1.4
|
||||
*
|
||||
* @param \PHP_CodeSniffer_File $phpcsFile The file being scanned.
|
||||
* @param int $stackPtr The position of the current token in
|
||||
* the stack passed in $tokens.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function processFunctionToken(File $phpcsFile, $stackPtr)
|
||||
{
|
||||
// Retrieve typehints stripped of global NS indicator and/or nullable indicator.
|
||||
$typeHints = $this->getTypeHintsFromFunctionDeclaration($phpcsFile, $stackPtr);
|
||||
if (empty($typeHints) || \is_array($typeHints) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($typeHints as $hint) {
|
||||
|
||||
$typeHintLc = strtolower($hint);
|
||||
|
||||
if (isset($this->newClasses[$typeHintLc]) === true) {
|
||||
$itemInfo = array(
|
||||
'name' => $hint,
|
||||
'nameLc' => $typeHintLc,
|
||||
);
|
||||
$this->handleFeature($phpcsFile, $stackPtr, $itemInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes this test for when a catch token is encountered.
|
||||
*
|
||||
* - Detect exceptions when used in a catch statement.
|
||||
*
|
||||
* @since 7.1.4
|
||||
*
|
||||
* @param \PHP_CodeSniffer_File $phpcsFile The file being scanned.
|
||||
* @param int $stackPtr The position of the current token in
|
||||
* the stack passed in $tokens.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function processCatchToken(File $phpcsFile, $stackPtr)
|
||||
{
|
||||
$tokens = $phpcsFile->getTokens();
|
||||
|
||||
// Bow out during live coding.
|
||||
if (isset($tokens[$stackPtr]['parenthesis_opener'], $tokens[$stackPtr]['parenthesis_closer']) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$opener = $tokens[$stackPtr]['parenthesis_opener'];
|
||||
$closer = ($tokens[$stackPtr]['parenthesis_closer'] + 1);
|
||||
$name = '';
|
||||
$listen = array(
|
||||
// Parts of a (namespaced) class name.
|
||||
\T_STRING => true,
|
||||
\T_NS_SEPARATOR => true,
|
||||
// End/split tokens.
|
||||
\T_VARIABLE => false,
|
||||
\T_BITWISE_OR => false,
|
||||
\T_CLOSE_CURLY_BRACKET => false, // Shouldn't be needed as we expect a var before this.
|
||||
);
|
||||
|
||||
for ($i = ($opener + 1); $i < $closer; $i++) {
|
||||
if (isset($listen[$tokens[$i]['code']]) === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($listen[$tokens[$i]['code']] === true) {
|
||||
$name .= $tokens[$i]['content'];
|
||||
continue;
|
||||
} else {
|
||||
if (empty($name) === true) {
|
||||
// Weird, we should have a name by the time we encounter a variable or |.
|
||||
// So this may be the closer.
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = ltrim($name, '\\');
|
||||
$nameLC = strtolower($name);
|
||||
|
||||
if (isset($this->newExceptions[$nameLC]) === true) {
|
||||
$itemInfo = array(
|
||||
'name' => $name,
|
||||
'nameLc' => $nameLC,
|
||||
);
|
||||
$this->handleFeature($phpcsFile, $i, $itemInfo);
|
||||
}
|
||||
|
||||
// Reset for a potential multi-catch.
|
||||
$name = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes this test for when a return type token is encountered.
|
||||
*
|
||||
* - Detect new classes when used as a return type declaration.
|
||||
*
|
||||
* @since 8.2.0
|
||||
*
|
||||
* @param \PHP_CodeSniffer_File $phpcsFile The file being scanned.
|
||||
* @param int $stackPtr The position of the current token in
|
||||
* the stack passed in $tokens.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function processReturnTypeToken(File $phpcsFile, $stackPtr)
|
||||
{
|
||||
$returnTypeHint = $this->getReturnTypeHintName($phpcsFile, $stackPtr);
|
||||
if (empty($returnTypeHint)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$returnTypeHint = ltrim($returnTypeHint, '\\');
|
||||
$returnTypeHintLc = strtolower($returnTypeHint);
|
||||
|
||||
if (isset($this->newClasses[$returnTypeHintLc]) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Still here ? Then this is a return type declaration using a new class.
|
||||
$itemInfo = array(
|
||||
'name' => $returnTypeHint,
|
||||
'nameLc' => $returnTypeHintLc,
|
||||
);
|
||||
$this->handleFeature($phpcsFile, $stackPtr, $itemInfo);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the relevant sub-array for a specific item from a multi-dimensional array.
|
||||
*
|
||||
* @since 7.1.0
|
||||
*
|
||||
* @param array $itemInfo Base information about the item.
|
||||
*
|
||||
* @return array Version and other information about the item.
|
||||
*/
|
||||
public function getItemArray(array $itemInfo)
|
||||
{
|
||||
return $this->newClasses[$itemInfo['nameLc']];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the error message template for this sniff.
|
||||
*
|
||||
* @since 7.1.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getErrorMsgTemplate()
|
||||
{
|
||||
return 'The built-in class ' . parent::getErrorMsgTemplate();
|
||||
}
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
/**
|
||||
* PHPCompatibility, an external standard for PHP_CodeSniffer.
|
||||
*
|
||||
* @package PHPCompatibility
|
||||
* @copyright 2012-2019 PHPCompatibility Contributors
|
||||
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
|
||||
* @link https://github.com/PHPCompatibility/PHPCompatibility
|
||||
*/
|
||||
|
||||
namespace PHPCompatibility\Sniffs\Classes;
|
||||
|
||||
use PHPCompatibility\Sniff;
|
||||
use PHP_CodeSniffer_File as File;
|
||||
use PHP_CodeSniffer_Tokens as Tokens;
|
||||
|
||||
/**
|
||||
* Visibility for class constants is available since PHP 7.1.
|
||||
*
|
||||
* PHP version 7.1
|
||||
*
|
||||
* @link https://wiki.php.net/rfc/class_const_visibility
|
||||
* @link https://www.php.net/manual/en/language.oop5.constants.php#language.oop5.basic.class.this
|
||||
*
|
||||
* @since 7.0.7
|
||||
*/
|
||||
class NewConstVisibilitySniff extends Sniff
|
||||
{
|
||||
/**
|
||||
* Returns an array of tokens this test wants to listen for.
|
||||
*
|
||||
* @since 7.0.7
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
return array(\T_CONST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes this test, when one of its tokens is encountered.
|
||||
*
|
||||
* @since 7.0.7
|
||||
*
|
||||
* @param \PHP_CodeSniffer_File $phpcsFile The file being scanned.
|
||||
* @param int $stackPtr The position of the current token
|
||||
* in the stack passed in $tokens.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function process(File $phpcsFile, $stackPtr)
|
||||
{
|
||||
if ($this->supportsBelow('7.0') === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tokens = $phpcsFile->getTokens();
|
||||
$prevToken = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true, null, true);
|
||||
|
||||
// Is the previous token a visibility indicator ?
|
||||
if ($prevToken === false || isset(Tokens::$scopeModifiers[$tokens[$prevToken]['code']]) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Is this a class constant ?
|
||||
if ($this->isClassConstant($phpcsFile, $stackPtr) === false) {
|
||||
// This may be a constant declaration in the global namespace with visibility,
|
||||
// but that would throw a parse error, i.e. not our concern.
|
||||
return;
|
||||
}
|
||||
|
||||
$phpcsFile->addError(
|
||||
'Visibility indicators for class constants are not supported in PHP 7.0 or earlier. Found "%s const"',
|
||||
$stackPtr,
|
||||
'Found',
|
||||
array($tokens[$prevToken]['content'])
|
||||
);
|
||||
}
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
/**
|
||||
* PHPCompatibility, an external standard for PHP_CodeSniffer.
|
||||
*
|
||||
* @package PHPCompatibility
|
||||
* @copyright 2012-2019 PHPCompatibility Contributors
|
||||
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
|
||||
* @link https://github.com/PHPCompatibility/PHPCompatibility
|
||||
*/
|
||||
|
||||
namespace PHPCompatibility\Sniffs\Classes;
|
||||
|
||||
use PHPCompatibility\Sniff;
|
||||
use PHP_CodeSniffer_File as File;
|
||||
use PHP_CodeSniffer_Tokens as Tokens;
|
||||
|
||||
/**
|
||||
* Detect use of late static binding as introduced in PHP 5.3.
|
||||
*
|
||||
* Checks for:
|
||||
* - Late static binding as introduced in PHP 5.3.
|
||||
* - Late static binding being used outside of class scope (unsupported).
|
||||
*
|
||||
* PHP version 5.3
|
||||
*
|
||||
* @link https://www.php.net/manual/en/language.oop5.late-static-bindings.php
|
||||
* @link https://wiki.php.net/rfc/lsb_parentself_forwarding
|
||||
*
|
||||
* @since 7.0.3
|
||||
* @since 9.0.0 Renamed from `LateStaticBindingSniff` to `NewLateStaticBindingSniff`.
|
||||
*/
|
||||
class NewLateStaticBindingSniff extends Sniff
|
||||
{
|
||||
/**
|
||||
* Returns an array of tokens this test wants to listen for.
|
||||
*
|
||||
* @since 7.0.3
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
return array(\T_STATIC);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes this test, when one of its tokens is encountered.
|
||||
*
|
||||
* @since 7.0.3
|
||||
*
|
||||
* @param \PHP_CodeSniffer_File $phpcsFile The file being scanned.
|
||||
* @param int $stackPtr The position of the current token in the
|
||||
* stack passed in $tokens.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function process(File $phpcsFile, $stackPtr)
|
||||
{
|
||||
$nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, $stackPtr + 1, null, true, null, true);
|
||||
if ($nextNonEmpty === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tokens = $phpcsFile->getTokens();
|
||||
if ($tokens[$nextNonEmpty]['code'] !== \T_DOUBLE_COLON) {
|
||||
return;
|
||||
}
|
||||
|
||||
$inClass = $this->inClassScope($phpcsFile, $stackPtr, false);
|
||||
|
||||
if ($inClass === true && $this->supportsBelow('5.2') === true) {
|
||||
$phpcsFile->addError(
|
||||
'Late static binding is not supported in PHP 5.2 or earlier.',
|
||||
$stackPtr,
|
||||
'Found'
|
||||
);
|
||||
}
|
||||
|
||||
if ($inClass === false) {
|
||||
$phpcsFile->addError(
|
||||
'Late static binding is not supported outside of class scope.',
|
||||
$stackPtr,
|
||||
'OutsideClassScope'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
/**
|
||||
* PHPCompatibility, an external standard for PHP_CodeSniffer.
|
||||
*
|
||||
* @package PHPCompatibility
|
||||
* @copyright 2012-2019 PHPCompatibility Contributors
|
||||
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
|
||||
* @link https://github.com/PHPCompatibility/PHPCompatibility
|
||||
*/
|
||||
|
||||
namespace PHPCompatibility\Sniffs\Classes;
|
||||
|
||||
use PHPCompatibility\Sniff;
|
||||
use PHP_CodeSniffer_File as File;
|
||||
use PHP_CodeSniffer_Tokens as Tokens;
|
||||
|
||||
/**
|
||||
* Typed class property declarations are available since PHP 7.4.
|
||||
*
|
||||
* PHP version 7.4
|
||||
*
|
||||
* @link https://www.php.net/manual/en/migration74.new-features.php#migration74.new-features.core.typed-properties
|
||||
* @link https://wiki.php.net/rfc/typed_properties_v2
|
||||
*
|
||||
* @since 9.2.0
|
||||
*/
|
||||
class NewTypedPropertiesSniff extends Sniff
|
||||
{
|
||||
|
||||
/**
|
||||
* Valid property modifier keywords.
|
||||
*
|
||||
* @since 9.2.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $modifierKeywords = array(
|
||||
\T_PRIVATE => \T_PRIVATE,
|
||||
\T_PROTECTED => \T_PROTECTED,
|
||||
\T_PUBLIC => \T_PUBLIC,
|
||||
\T_STATIC => \T_STATIC,
|
||||
\T_VAR => \T_VAR,
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of tokens this test wants to listen for.
|
||||
*
|
||||
* @since 9.2.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
return array(\T_VARIABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes this test, when one of its tokens is encountered.
|
||||
*
|
||||
* @since 9.2.0
|
||||
*
|
||||
* @param \PHP_CodeSniffer_File $phpcsFile The file being scanned.
|
||||
* @param int $stackPtr The position of the current token in the
|
||||
* stack passed in $tokens.
|
||||
*
|
||||
* @return int|void Integer stack pointer to skip forward or void to continue
|
||||
* normal file processing.
|
||||
*/
|
||||
public function process(File $phpcsFile, $stackPtr)
|
||||
{
|
||||
if ($this->isClassProperty($phpcsFile, $stackPtr) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$find = $this->modifierKeywords;
|
||||
$find += array(
|
||||
\T_SEMICOLON => \T_SEMICOLON,
|
||||
\T_OPEN_CURLY_BRACKET => \T_OPEN_CURLY_BRACKET,
|
||||
);
|
||||
|
||||
$tokens = $phpcsFile->getTokens();
|
||||
$modifier = $phpcsFile->findPrevious($find, ($stackPtr - 1));
|
||||
if ($modifier === false
|
||||
|| $tokens[$modifier]['code'] === \T_SEMICOLON
|
||||
|| $tokens[$modifier]['code'] === \T_OPEN_CURLY_BRACKET
|
||||
) {
|
||||
// Parse error. Ignore.
|
||||
return;
|
||||
}
|
||||
|
||||
$type = $phpcsFile->findNext(Tokens::$emptyTokens, ($modifier + 1), null, true);
|
||||
if ($tokens[$type]['code'] === \T_VARIABLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Still here ? In that case, this will be a typed property.
|
||||
if ($this->supportsBelow('7.3') === true) {
|
||||
$phpcsFile->addError(
|
||||
'Typed properties are not supported in PHP 7.3 or earlier',
|
||||
$type,
|
||||
'Found'
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->supportsAbove('7.4') === true) {
|
||||
// Examine the type to verify it's valid.
|
||||
if ($tokens[$type]['type'] === 'T_NULLABLE'
|
||||
// Needed to support PHPCS < 3.5.0 which doesn't correct to the nullable token type yet.
|
||||
|| $tokens[$type]['code'] === \T_INLINE_THEN
|
||||
) {
|
||||
$type = $phpcsFile->findNext(Tokens::$emptyTokens, ($type + 1), null, true);
|
||||
}
|
||||
|
||||
$content = $tokens[$type]['content'];
|
||||
if ($content === 'void' || $content === 'callable') {
|
||||
$phpcsFile->addError(
|
||||
'%s is not supported as a type declaration for properties',
|
||||
$type,
|
||||
'InvalidType',
|
||||
array($content)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$endOfStatement = $phpcsFile->findNext(\T_SEMICOLON, ($stackPtr + 1));
|
||||
if ($endOfStatement !== false) {
|
||||
// Don't throw the same error multiple times for multi-property declarations.
|
||||
return ($endOfStatement + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
/**
|
||||
* PHPCompatibility, an external standard for PHP_CodeSniffer.
|
||||
*
|
||||
* @package PHPCompatibility
|
||||
* @copyright 2012-2019 PHPCompatibility Contributors
|
||||
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
|
||||
* @link https://github.com/PHPCompatibility/PHPCompatibility
|
||||
*/
|
||||
|
||||
namespace PHPCompatibility\Sniffs\Classes;
|
||||
|
||||
use PHPCompatibility\Sniff;
|
||||
use PHP_CodeSniffer_File as File;
|
||||
|
||||
/**
|
||||
* Using `parent` inside a class without parent is deprecated since PHP 7.4.
|
||||
*
|
||||
* This will throw a compile-time error in the future. Currently an error will only
|
||||
* be generated if/when the parent is accessed at run-time.
|
||||
*
|
||||
* PHP version 7.4
|
||||
*
|
||||
* @link https://www.php.net/manual/en/migration74.deprecated.php#migration74.deprecated.core.parent
|
||||
*
|
||||
* @since 9.2.0
|
||||
*/
|
||||
class RemovedOrphanedParentSniff extends Sniff
|
||||
{
|
||||
|
||||
/**
|
||||
* Class scopes to check the class declaration.
|
||||
*
|
||||
* @since 9.2.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $classScopeTokens = array(
|
||||
'T_CLASS' => true,
|
||||
'T_ANON_CLASS' => true,
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns an array of tokens this test wants to listen for.
|
||||
*
|
||||
* @since 9.2.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
return array(\T_PARENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes this test, when one of its tokens is encountered.
|
||||
*
|
||||
* @since 9.2.0
|
||||
*
|
||||
* @param \PHP_CodeSniffer_File $phpcsFile The file being scanned.
|
||||
* @param int $stackPtr The position of the current token
|
||||
* in the stack passed in $tokens.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function process(File $phpcsFile, $stackPtr)
|
||||
{
|
||||
if ($this->supportsAbove('7.4') === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tokens = $phpcsFile->getTokens();
|
||||
|
||||
if (empty($tokens[$stackPtr]['conditions']) === true) {
|
||||
// Use within the global namespace. Not our concern.
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the class within which this parent keyword is used.
|
||||
*/
|
||||
$conditions = $tokens[$stackPtr]['conditions'];
|
||||
$conditions = array_reverse($conditions, true);
|
||||
$classPtr = false;
|
||||
|
||||
foreach ($conditions as $ptr => $type) {
|
||||
if (isset($this->classScopeTokens[$tokens[$ptr]['type']])) {
|
||||
$classPtr = $ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($classPtr === false) {
|
||||
// Use outside of a class scope. Not our concern.
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($tokens[$classPtr]['scope_opener']) === false) {
|
||||
// No scope opener known. Probably a parse error.
|
||||
return;
|
||||
}
|
||||
|
||||
$extends = $phpcsFile->findNext(\T_EXTENDS, ($classPtr + 1), $tokens[$classPtr]['scope_opener']);
|
||||
if ($extends !== false) {
|
||||
// Class has a parent.
|
||||
return;
|
||||
}
|
||||
|
||||
$phpcsFile->addError(
|
||||
'Using "parent" inside a class without parent is deprecated since PHP 7.4',
|
||||
$stackPtr,
|
||||
'Deprecated'
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user