Code Monkey home page Code Monkey logo

php_codesniffer's People

Contributors

aboks avatar alekitto avatar andygrunwald avatar biinari avatar bondas83 avatar dependabot[bot] avatar dingo-d avatar fabacino avatar fredden avatar gmponos avatar gsherwood avatar josephzidell avatar jrfnl avatar klausi avatar kukulich avatar masterodin avatar michalbundyra avatar morozov avatar nubs avatar phil-davis avatar photodude avatar rmccue avatar rodrigoprimo avatar sebastianbergmann avatar sertand avatar thewilkybarkid avatar thiemowmde avatar tim-bezhashvyly avatar vincentlanglet avatar wimg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

php_codesniffer's Issues

PSR12.Files.FileHeader: false positive when there is no header

Repost from squizlabs/PHP_CodeSniffer#2997:

Given the following code run against the PSR12 standard:

<?php

/*
 * Not a file docblock.
 */

/**
 * Docblock for an include statement.
 */
include 'foo.php';

I get the following error:

--------------------------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
--------------------------------------------------------------------------------------
 9 | ERROR | [x] Header blocks must be separated by a single blank line
   |       |     (PSR12.Files.FileHeader.SpacingAfterBlock)

... while I expected none.


See the original thread for additional information.

PHP 8.0 | Tokenizer: Handle reserved keywords being used in namespaced names

Repost from squizlabs/PHP_CodeSniffer#3336:

PR #3063 and it's PHPCS 4.x sister-PR addressed the namespaced name token changes as outlined in #3041.

The underlying PHP RFC, however, contains another change which is so far unaccounted for: reserved keywords can now be used in namespaced names.

The impact of this change is limited to PHP 8.0 code which actually uses reserved keywords in namespaced names, so the fact that PHPCS does not handle this yet, will probably not affect many people for now.

I've been doing some research to see what the impact is of this and have come to the conclusion that we will need to adjust the tokenizer for this in PHPCS 3.x.
With the retokenization to the PHP 8 tokens in PHPCS 4.x, I expect that there will be far less issues in PHPCS 4.x, though a slightly different fix may still be needed there too, but I will check that later just to be sure.

The problem is two-fold:

PHP 8.0

When PHPCS is run on PHP 8.0, single-level namespace names and single-level within a group use statement, are the only ones which will really cause a problem. Note: the below code sample is valid PHP 8.0 code.

namespace Class;

use Foreach;

use Package\{
    Include
};

The examples from the above code sample are likely to also cause issues in PHPCS 4.x, but I expect that those will be the only problem cases in PHPCS 4.x.

Multi-level namespace names are split into T_STRING tokens separated by T_NS_SEPARATOR tokens, independently of the token content, so reserved keywords in multi-level namespaced names are not affected. See PR #3063.

PHP 5.4-7.4

When PHPCS is run on PHP 5.4-7.4 against code written for PHP 8.0, the problem is much more extensive as reserved keywords used in namespaced names will, in that case, always tokenize as their keyword token, which will cause lots of sniffs looking for a particular keyword to throw false positives and will cause at least one sniff to go into an infinite loop (which sniff is still to be identified).

namespace For\Include\Class;

use Goto\Interface;

\Echo\Private\function_name();

Sniffs which are impacted by this.

The below lists are based on an initial scan with some test code against all PHPCS native standards. This type of scan will only show false positives, not false negatives, so in practice, there are likely to be more sniffs affected, but these lists give some indication of the problem.

As some of these sniffs contain auto-fixers, it can be presumed that the result of running phpcbf on PHP 8.0 code using reserved keywords in namespace names will cause the fixers to introduce parse errors into the code.

Also, these lists are limited to the PHPCS native sniffs, while sniffs in external standards will, of course, also be affected.

When running PHPCS on PHP 8.0

  • Generic.Arrays.DisallowLongArraySyntax
  • Generic.Classes.OpeningBraceSameLine
  • Generic.ControlStructures.InlineControlStructure
  • Generic.Files.OneObjectStructurePerFile
  • Generic.NamingConventions.InterfaceNameSuffix
  • Generic.PHP.DiscourageGoto
  • PEAR.Classes.ClassDeclaration
  • PEAR.Commenting.ClassComment
  • PEAR.Commenting.FunctionComment
  • PEAR.Files.IncludingFile
  • PEAR.NamingConventions.ValidClassName
  • PSR2.Classes.ClassDeclaration
  • PSR2.Namespaces.UseDeclaration
  • PSR12.Classes.ClassInstantiation
  • PSR12.Files.DeclareStatement
  • PSR12.Files.ImportStatement
  • PSR12.Operators.OperatorSpacing
  • Squiz.Classes.ValidClassName
  • Squiz.ControlStructures.ForEachLoopDeclaration
  • Squiz.ControlStructures.ForLoopDeclaration
  • Squiz.Files.FileExtension
  • Squiz.WhiteSpace.ScopeKeywordSpacing
  • Squiz.ControlStructures.ForEachLoopDeclaration
  • Squiz.ControlStructures.ForLoopDeclaration
  • Squiz.Functions.GlobalFunction
  • Squiz.Operators.ValidLogicalOperators
  • Squiz.PHP.DisallowBooleanStatement
  • Squiz.WhiteSpace.LogicalOperatorSpacing

There is also at least one sniff (in the Squiz standard) which causes an Internal.Exception

When running PHPCS on PHP 5.4-7.4

(partial list as the PSR1, PSR2, PSR12 and Squiz standards go into an infinite loop)

  • Generic.Arrays.DisallowLongArraySyntax
  • Generic.Classes.OpeningBraceSameLine
  • Generic.CodeAnalysis.UnconditionalIfStatement
  • Generic.ControlStructures.InlineControlStructure
  • Generic.Files.OneObjectStructurePerFile
  • Generic.Functions.OpeningFunctionBraceBsdAllman
  • Generic.NamingConventions.CamelCapsFunctionName
  • Generic.NamingConventions.InterfaceNameSuffix
  • Generic.NamingConventions.TraitNameSuffix
  • Generic.PHP.DiscourageGoto
  • Generic.WhiteSpace.LanguageConstructSpacing
  • Generic.WhiteSpace.ScopeIndent
  • PEAR.Classes.ClassDeclaration
  • PEAR.Commenting.ClassComment
  • PEAR.Commenting.FunctionComment
  • PEAR.ControlStructures.ControlSignature
  • PEAR.Files.IncludingFile
  • PEAR.Functions.FunctionDeclaration
  • PEAR.NamingConventions.ValidClassName
  • PEAR.NamingConventions.ValidFunctionName
  • PEAR.WhiteSpace.ScopeIndent
  • PEAR.WhiteSpace.ScopeClosingBrace
  • Squiz.Functions.GlobalFunction

Proposed fix

I propose to add code to the Tokenizer\PHP class to retokenize reserved keywords used in namespace(d) names to T_STRING.

A similar, but far more limited fix will need to be applied to PHPCS 4.x for single-level namespace name use.


PR #3484 and its follow-ups should have fixed the majority of issues, but it would still be good to verify this.

`// phpcs:set` is not limited to the file in which it is used

Repost from squizlabs/PHP_CodeSniffer#2126:

I may be missing something, but AFAICS and in contrast to the other //phpcs: annotations, using // phpcs:set Standard.Category.Sniff PropertyName value is not file-based, but changes the sniff property for the rest of the PHPCS run.

IMHO this is unreliable as the effect of this depends on:

  1. the order in which the files are sniffed which may change without notice;
  2. will not work as expected when used in combination with the parallel option.

While in practice, this feature is mostly used in PHPCS unit tests, it is a useful feature as there is no other way to set a property for a limited group of files.

Would it be possible to make the effect of the // phpcs:set annotation be file-based ?

I imagine, that this could be done by saving the original value of the property when the first // phpcs:set for a certain property in a file is encountered into an array like $propertyOverrides[$sniffName][$propertyName] = $originalValue; and resetting the property to that original value once the last token of a file has been reached (or something along those lines).

Example use-case:

Say I have a sniff which checks variables in the global namespace or within a function scope when a global statement is encountered.

Now , say a project has view files which are included from within a function in another file. For those files it would be useful to be able to set a property FileType view which would only apply to that file.
That way, for that file, the "global" namespace could be treated as scoped and the sniff would only check the variables and throw errors when a global statement is encountered.

Using phpcs:disable for that file or <exclude-pattern> the file from within a custom ruleset, is not an option as that would disable the sniff completely.

But setting phpcs:set at the top of the file currently changes the behaviour of the sniff for that file and all files scanned after it, which is not the intention either.


See the original discussion for some additional input.

Docs: add more information about `parallel` option

Repost from squizlabs/PHP_CodeSniffer#1732:

I've just been looking into the parallel running option a bit more and am left with some questions.

  • When should you use this option ?
  • Does it work equally well with phpcs as well as phpcbf ?
  • What things should you take into consideration when determining the amount of parallel processes to use ?
  • What can go wrong ? Are there any type of sniffs which would be incompatible with parallel processing ?
  • Any thing else which behaves differently if parallel processing is turned on ?

It might be useful to add a section to the Wiki Advanced Usage page about this.


👉🏻 The thread in the original post contains lots of useful comments and would be a good starting point to start writing this up.

QA: standards should not have conflicting rules / fix fixer conflicts

Premise

A standard should be able to be used without leading to fixer conflicts.

Now, as code can be written in lots of different ways, it is not always straight forward to anticipate potential conflicts, however, PHPCS contains a wealth of test code, so by running the fixers for a standard over all test case files, we should be able to detect a lot of potential fixer conflicts.

Current status

While I have the workflow and the set up for this check ready, it cannot currently be turned on as all standards, except PSR1, lead to fixer conflicts.

Note: as CSS/JS support will be dropped in v 4.0, I've not included the CSS/JS test case files in the set up for the fixer conflict check.

Also note that Generic is not a standard but a sniff collection containing conflicting rules by design. For that reason, the fixer conflict check is not relevant.

Last update date for the "current status": 2024-07-29
Please feel free to ping @jrfnl for an update if the list is outdated.

Details of current fixer conflicts for the PEAR standard

Command:

phpcbf -p . --standard=PEAR --ignore=*/build/*,*/vendor/* --basepath=. --extensions=inc --suffix=.conflictcheck

Test case files leading to fixer conflicts

PHPCBF RESULT SUMMARY
------------------------------------------------------------------------------------------------------------------
FILE                                                                                              FIXED  REMAINING
------------------------------------------------------------------------------------------------------------------
src\Standards\Generic\Tests\ControlStructures\DisallowYodaConditionsUnitTest.inc                  FAILED TO FIX
src\Standards\Generic\Tests\WhiteSpace\ScopeIndentUnitTest.1.inc                                  FAILED TO FIX
src\Standards\Generic\Tests\WhiteSpace\ScopeIndentUnitTest.2.inc                                  FAILED TO FIX
src\Standards\PEAR\Tests\NamingConventions\ValidVariableNameUnitTest.inc                          FAILED TO FIX
src\Standards\PEAR\Tests\WhiteSpace\ScopeClosingBraceUnitTest.inc                                 FAILED TO FIX
src\Standards\PSR12\Tests\Functions\ReturnTypeDeclarationUnitTest.inc                             FAILED TO FIX
src\Standards\PSR2\Tests\ControlStructures\SwitchDeclarationUnitTest.inc                          FAILED TO FIX
src\Standards\Squiz\Tests\Commenting\LongConditionClosingCommentUnitTest.inc                      FAILED TO FIX
src\Standards\Squiz\Tests\PHP\NonExecutableCodeUnitTest.1.inc                                     FAILED TO FIX
src\Standards\Squiz\Tests\WhiteSpace\ScopeClosingBraceUnitTest.inc                                FAILED TO FIX
tests\Core\File\FindEndOfStatementTest.inc                                                        FAILED TO FIX
tests\Core\File\FindStartOfStatementTest.inc                                                      FAILED TO FIX
tests\Core\File\GetMethodPropertiesTest.inc                                                       FAILED TO FIX **NEW 2024-03
tests\Core\Tokenizer\PHP\DefaultKeywordTest.inc                                                   FAILED TO FIX
tests\Core\Tokenizer\PHP\DNFTypesParseError1Test.inc                                              FAILED TO FIX **NEW 2024-07
tests\Core\Tokenizer\PHP\EnumCaseTest.inc                                                         FAILED TO FIX
tests\Core\Tokenizer\Tokenizer\RecurseScopeMapCaseKeywordConditionsTest.inc                       FAILED TO FIX **NEW 2024-07
tests\Core\Tokenizer\Tokenizer\RecurseScopeMapDefaultKeywordConditionsTest.inc                    FAILED TO FIX **NEW 2024-07
------------------------------------------------------------------------------------------------------------------
A TOTAL OF 9881 ERRORS WERE FIXED IN 315 FILES
------------------------------------------------------------------------------------------------------------------
PHPCBF FAILED TO FIX 18 FILES
------------------------------------------------------------------------------------------------------------------
Details of current fixer conflicts for the PSR2 standard

Command:

phpcbf -p . --standard=PSR2 --ignore=*/build/*,*/vendor/* --basepath=. --extensions=inc --suffix=.conflictcheck

Test case files leading to fixer conflicts

PHPCBF RESULT SUMMARY
------------------------------------------------------------------------------------------------------------------
FILE                                                                                              FIXED  REMAINING
------------------------------------------------------------------------------------------------------------------
src\Standards\Generic\Tests\CodeAnalysis\JumbledIncrementerUnitTest.4.inc                         FAILED TO FIX **NEW 2024-07
src\Standards\PEAR\Tests\Functions\FunctionCallSignatureUnitTest.inc                              FAILED TO FIX
src\Standards\PSR12\Tests\Functions\ReturnTypeDeclarationUnitTest.inc                             FAILED TO FIX
src\Standards\Squiz\Tests\Classes\SelfMemberReferenceUnitTest.inc                                 FAILED TO FIX **NEW 2024-07
src\Standards\Squiz\Tests\ControlStructures\ForEachLoopDeclarationUnitTest.inc                    FAILED TO FIX
tests\Core\File\GetMethodPropertiesTest.inc                                                       FAILED TO FIX **NEW 2024-03
tests\Core\Tokenizer\PHP\DNFTypesParseError1Test.inc                                              FAILED TO FIX **NEW 2024-07
------------------------------------------------------------------------------------------------------------------
A TOTAL OF 9637 ERRORS WERE FIXED IN 366 FILES
------------------------------------------------------------------------------------------------------------------
PHPCBF FAILED TO FIX 7 FILES
------------------------------------------------------------------------------------------------------------------
Details of current fixer conflicts for the PSR12 standard

Command:

phpcbf -p . --standard=PSR12 --ignore=*/build/*,*/vendor/* --basepath=. --extensions=inc --suffix=.conflictcheck

Test case files leading to fixer conflicts

PHPCBF RESULT SUMMARY
-----------------------------------------------------------------------------------------------------------
FILE                                                                                       FIXED  REMAINING
-----------------------------------------------------------------------------------------------------------
src\Standards\Generic\Tests\PHP\RequireStrictTypesUnitTest.13.inc                          FAILED TO FIX
src\Standards\Generic\Tests\PHP\RequireStrictTypesUnitTest.5.inc                           FAILED TO FIX
src\Standards\PEAR\Tests\Functions\FunctionCallSignatureUnitTest.inc                       FAILED TO FIX
src\Standards\PSR12\Tests\Functions\ReturnTypeDeclarationUnitTest.inc                      FAILED TO FIX
src\Standards\Squiz\Tests\ControlStructures\ForEachLoopDeclarationUnitTest.inc             FAILED TO FIX
src\Standards\Squiz\Tests\ControlStructures\ForLoopDeclarationUnitTest.inc                 FAILED TO FIX
tests\Core\File\GetMethodParametersTest.inc                                                FAILED TO FIX
tests\Core\Tokenizer\ScopeSettingWithNamespaceOperatorTest.inc                             FAILED TO FIX
tests\Core\Tokenizer\UndoNamespacedNameSingleTokenTest.inc                                 FAILED TO FIX
-----------------------------------------------------------------------------------------------------------
A TOTAL OF 10594 ERRORS WERE FIXED IN 372 FILES
-----------------------------------------------------------------------------------------------------------
PHPCBF FAILED TO FIX 9 FILES
-----------------------------------------------------------------------------------------------------------
Details of current fixer conflicts for the Squiz standard

Command:

phpcbf -p . --standard=Squiz --ignore=*/build/*,*/vendor/* --basepath=. --extensions=inc --suffix=.conflictcheck

Test case files leading to fixer conflicts

PHPCBF RESULT SUMMARY
------------------------------------------------------------------------------------------------------------------
FILE                                                                                              FIXED  REMAINING
------------------------------------------------------------------------------------------------------------------
src\Standards\Generic\Tests\Arrays\ArrayIndentUnitTest.inc                                        FAILED TO FIX
src\Standards\Generic\Tests\Classes\DuplicateClassNameUnitTest.3.inc                              FAILED TO FIX
src\Standards\Generic\Tests\CodeAnalysis\EmptyPHPStatementUnitTest.inc                            FAILED TO FIX
src\Standards\Generic\Tests\CodeAnalysis\JumbledIncrementerUnitTest.4.inc                         FAILED TO FIX **NEW 2024-07
src\Standards\Generic\Tests\CodeAnalysis\UselessOverridingMethodUnitTest.1.inc                    FAILED TO FIX **NEW 2024-03
src\Standards\Generic\Tests\ControlStructures\DisallowYodaConditionsUnitTest.inc                  FAILED TO FIX
src\Standards\Generic\Tests\ControlStructures\InlineControlStructureUnitTest.1.inc                FAILED TO FIX **NEW 2024-07
src\Standards\Generic\Tests\Functions\FunctionCallArgumentSpacingUnitTest.1.inc                   FAILED TO FIX **NEW 2024-07
src\Standards\Generic\Tests\NamingConventions\AbstractClassNamePrefixUnitTest.inc                 FAILED TO FIX
src\Standards\Generic\Tests\PHP\CharacterBeforePHPOpeningTagUnitTest.1.inc                        FAILED TO FIX
src\Standards\Generic\Tests\WhiteSpace\ScopeIndentUnitTest.1.inc                                  FAILED TO FIX
src\Standards\Generic\Tests\WhiteSpace\ScopeIndentUnitTest.2.inc                                  FAILED TO FIX
src\Standards\PEAR\Tests\Classes\ClassDeclarationUnitTest.1.inc                                   FAILED TO FIX
src\Standards\PEAR\Tests\Classes\ClassDeclarationUnitTest.2.inc                                   FAILED TO FIX
src\Standards\PEAR\Tests\Commenting\ClassCommentUnitTest.inc                                      FAILED TO FIX
src\Standards\PEAR\Tests\Commenting\FunctionCommentUnitTest.inc                                   FAILED TO FIX
src\Standards\PEAR\Tests\ControlStructures\MultiLineConditionUnitTest.inc                         FAILED TO FIX
src\Standards\PEAR\Tests\Functions\FunctionCallSignatureUnitTest.inc                              FAILED TO FIX
src\Standards\PEAR\Tests\Functions\FunctionDeclarationUnitTest.1.inc                              FAILED TO FIX
src\Standards\PEAR\Tests\NamingConventions\ValidVariableNameUnitTest.inc                          FAILED TO FIX
src\Standards\PEAR\Tests\WhiteSpace\ScopeClosingBraceUnitTest.inc                                 FAILED TO FIX **NEW 2024-03
src\Standards\PSR1\Tests\Files\SideEffectsUnitTest.1.inc                                          FAILED TO FIX
src\Standards\PSR12\Tests\ControlStructures\BooleanOperatorPlacementUnitTest.inc                  FAILED TO FIX
src\Standards\PSR12\Tests\Functions\ReturnTypeDeclarationUnitTest.inc                             FAILED TO FIX
src\Standards\PSR12\Tests\Operators\OperatorSpacingUnitTest.1.inc                                 FAILED TO FIX
src\Standards\PSR2\Tests\Classes\ClassDeclarationUnitTest.inc                                     FAILED TO FIX
src\Standards\PSR2\Tests\ControlStructures\ControlStructureSpacingUnitTest.inc                    FAILED TO FIX
src\Standards\PSR2\Tests\Methods\FunctionCallSignatureUnitTest.inc                                FAILED TO FIX
src\Standards\Squiz\Tests\Arrays\ArrayDeclarationUnitTest.1.inc                                   FAILED TO FIX
src\Standards\Squiz\Tests\Arrays\ArrayDeclarationUnitTest.2.inc                                   FAILED TO FIX
src\Standards\Squiz\Tests\Classes\SelfMemberReferenceUnitTest.inc                                 FAILED TO FIX
src\Standards\Squiz\Tests\Commenting\ClassCommentUnitTest.inc                                     FAILED TO FIX
src\Standards\Squiz\Tests\Commenting\FunctionCommentThrowTagUnitTest.inc                          FAILED TO FIX
src\Standards\Squiz\Tests\Commenting\FunctionCommentUnitTest.inc                                  FAILED TO FIX
src\Standards\Squiz\Tests\Commenting\VariableCommentUnitTest.inc                                  FAILED TO FIX
src\Standards\Squiz\Tests\ControlStructures\ControlSignatureUnitTest.1.inc                        FAILED TO FIX
src\Standards\Squiz\Tests\ControlStructures\ForEachLoopDeclarationUnitTest.inc                    FAILED TO FIX
src\Standards\Squiz\Tests\ControlStructures\ForLoopDeclarationUnitTest.1.inc                      FAILED TO FIX
src\Standards\Squiz\Tests\Objects\ObjectInstantiationUnitTest.inc                                 FAILED TO FIX **NEW 2024-03
src\Standards\Squiz\Tests\PHP\EmbeddedPhpUnitTest.1.inc                                           FAILED TO FIX
src\Standards\Squiz\Tests\PHP\EmbeddedPhpUnitTest.19.inc                                          FAILED TO FIX **NEW 2024-03
src\Standards\Squiz\Tests\PHP\EmbeddedPhpUnitTest.5.inc                                           FAILED TO FIX **NEW 2024-03
src\Standards\Squiz\Tests\PHP\InnerFunctionsUnitTest.inc                                          FAILED TO FIX
src\Standards\Squiz\Tests\Scope\MemberVarScopeUnitTest.inc                                        FAILED TO FIX
src\Standards\Squiz\Tests\Scope\MethodScopeUnitTest.inc                                           FAILED TO FIX
src\Standards\Squiz\Tests\WhiteSpace\ControlStructureSpacingUnitTest.inc                          FAILED TO FIX
src\Standards\Squiz\Tests\WhiteSpace\FunctionSpacingUnitTest.1.inc                                FAILED TO FIX
src\Standards\Squiz\Tests\WhiteSpace\ScopeClosingBraceUnitTest.inc                                FAILED TO FIX
src\Standards\Squiz\Tests\WhiteSpace\ScopeKeywordSpacingUnitTest.1.inc                            FAILED TO FIX
src\Standards\Squiz\Tests\WhiteSpace\ScopeKeywordSpacingUnitTest.3.inc                            FAILED TO FIX
tests\Core\File\FindExtendedClassNameTest.inc                                                     FAILED TO FIX **NEW 2024-03
tests\Core\File\FindStartOfStatementTest.inc                                                      FAILED TO FIX
tests\Core\File\GetConditionTest.inc                                                              FAILED TO FIX **NEW 2024-03
tests\Core\File\GetDeclarationNameTest.inc                                                        FAILED TO FIX **NEW 2024-03
tests\Core\File\GetMemberPropertiesTest.inc                                                       FAILED TO FIX
tests\Core\File\GetMethodParametersTest.inc                                                       FAILED TO FIX
tests\Core\File\GetMethodPropertiesTest.inc                                                       FAILED TO FIX **NEW 2024-03
tests\Core\Tokenizer\PHP\AttributesTest.inc                                                       FAILED TO FIX
tests\Core\Tokenizer\PHP\BackfillMatchTokenTest.inc                                               FAILED TO FIX
tests\Core\Tokenizer\PHP\BackfillReadonlyTest.inc                                                 FAILED TO FIX **NEW 2024-03
tests\Core\Tokenizer\PHP\BitwiseOrTest.inc                                                        FAILED TO FIX
tests\Core\Tokenizer\PHP\ContextSensitiveKeywordsTest.inc                                         FAILED TO FIX
tests\Core\Tokenizer\PHP\DefaultKeywordTest.inc                                                   FAILED TO FIX
tests\Core\Tokenizer\PHP\DNFTypesParseError1Test.inc                                              FAILED TO FIX **NEW 2024-07
tests\Core\Tokenizer\PHP\DNFTypesTest.inc                                                         FAILED TO FIX **NEW 2024-07
tests\Core\Tokenizer\PHP\DoubleArrowTest.inc                                                      FAILED TO FIX
tests\Core\Tokenizer\PHP\EnumCaseTest.inc                                                         FAILED TO FIX
tests\Core\Tokenizer\PHP\TypeIntersectionTest.inc                                                 FAILED TO FIX
tests\Core\Tokenizer\Tokenizer\CreateParenthesisNestingMapDNFTypesTest.inc                        FAILED TO FIX **NEW 2024-07
tests\Core\Tokenizer\Tokenizer\RecurseScopeMapCaseKeywordConditionsTest.inc                       FAILED TO FIX **NEW 2024-07
tests\Core\Tokenizer\Tokenizer\RecurseScopeMapDefaultKeywordConditionsTest.inc                    FAILED TO FIX **NEW 2024-07
------------------------------------------------------------------------------------------------------------------
A TOTAL OF 26620 ERRORS WERE FIXED IN 471 FILES
------------------------------------------------------------------------------------------------------------------
PHPCBF FAILED TO FIX 71 FILES
------------------------------------------------------------------------------------------------------------------
Details of current fixer conflicts for the Zend standard

Command:

phpcbf -p . --standard=Zend --ignore=*/build/*,*/vendor/* --basepath=. --extensions=inc --suffix=.conflictcheck

Test case files leading to fixer conflicts

PHPCBF RESULT SUMMARY
-----------------------------------------------------------------------------------------------------------
FILE                                                                                       FIXED  REMAINING
-----------------------------------------------------------------------------------------------------------
src\Standards\Generic\Tests\Functions\FunctionCallArgumentSpacingUnitTest.1.inc            FAILED TO FIX
src\Standards\Generic\Tests\NamingConventions\ConstructorNameUnitTest.inc                  FAILED TO FIX
src\Standards\Generic\Tests\WhiteSpace\ScopeIndentUnitTest.1.inc                           FAILED TO FIX
src\Standards\Generic\Tests\WhiteSpace\ScopeIndentUnitTest.2.inc                           FAILED TO FIX
src\Standards\Squiz\Tests\WhiteSpace\ScopeClosingBraceUnitTest.inc                         FAILED TO FIX
-----------------------------------------------------------------------------------------------------------
A TOTAL OF 6354 ERRORS WERE FIXED IN 328 FILES
-----------------------------------------------------------------------------------------------------------
PHPCBF FAILED TO FIX 5 FILES
-----------------------------------------------------------------------------------------------------------

Caveat

There are some files which should probably be excluded from a fixer conflict check like this ticket proposes. Most notably test case files which contain git merge conflict markers.

For the above lists in the fold-outs, this was already done.

What needs to be done

For each of the files listed above leading to a fixer conflict, it needs to be determined whether:

  1. The file should be excluded from the fixer conflict check; or
  2. The fixer conflict is a realistic situation which should be handled.

How to go about this

  • Add *.conflictcheck to your .git/info/exclude (will be added to .gitignore when the fixer conflict check will be added for real).
  • Run the command listed against one particular file from the conflict list with the -vvv flag.
  • The output will be long, but at the bottom you will find information about the conflicting sniffs.
  • Identify the piece of code in the test case file which is causing the conflict.
  • Look critically at the piece of code causing the conflict to determine whether this is a situation which:
    • should be handled by the sniffs;
    • whether the code snippet is an unintentional parse error, which should be fixed. This applies to unintentional typos in a test case in contrast to a test case specifically created as a parse error to test the handling within the sniff.
    • whether the code snippet is an intentional parse error and that particular piece of code should be moved to its own test case file and that file should be excluded (also see #143);
    • whether the existing test case file should be excluded.
  • If the sniffs should handle this gracefully, add the piece of code to the test case files for all sniffs involved.
  • Decide for each sniff how the issue should be handled. Oftentimes, the answer is adding more defensive coding and bowing out in certain circumstances, meaning one sniff takes precedence over another.

When in doubt, share your findings and discuss the options for the conflict you are working on in a comment on this ticket or create a separate ticket to discuss solution directions if the conflict is a complex one (and link that ticket to this one).

PRs for this task should only contain the solution for one fixer conflict per PR and if the conflict can be isolated enough, the PR should be limited to fixing the issue for only one of the sniffs involved, with, if necessary, separate PRs for the other sniff(s) involved.

False positive Generic.ControlStructures.DisallowYodaConditions

Repost from squizlabs/PHP_CodeSniffer#2962:

The Generic.ControlStructures.DisallowYodaConditions reports a Usage of Yoda conditions is not allowed; switch the expression order error for the below code, which IMO is incorrect (the error, not the code).

$var = ( (string) function_call( 'text' ) ) === '0';

@umherirrender provided a second code sample:

Another one:

					return ( $group && $pos ) ?
						( $pos % $group ) === 0 && ( $pos < 0 === $group < 0 ) :
						!$pos;

It seems that a boolean condition with two < 0 is not handled correctly by the sniff.

Work around: Add () around each part of the condition


@jlherren provided a third:

I'm also experiencing this, here's a very short example:

$a = 1 * (1 + 1) !== 0;

Docs: add missing XML documentation for sniffs

Sniffs in PHP_CodeSniffer should preferably be accompanied by documentation. There are currently still a number of sniffs which don't have documentation.

Sniff documentation is provided via XML files in the standard's Docs directory and is available to end-users via the command-line and/or can be compiled into an HTML or Markdown file.

To see an example of some of some available documentation, run:

phpcs --standard=PSR12 --generator=Text

Getting started

The CONTRIBUTING doc contains information on writing sniff documentation and guidelines which should be followed.

Action list

Blocked

  • PSR12.Files.DeclareStatement (There is a first draft available created by @dingo-d, which can be iterated on #187)
    Note: this one is blocked until the sniff rewrite has been finished & merged.

To Do

  • PSR12.Classes.AnonClassDeclaration (There is a first draft available created by @dingo-d, which can be iterated on #167)
  • PSR12.Files.FileHeader (There is a first draft available created by @dingo-d, which can be iterated on #231)
  • PSR12.Traits.UseDeclaration (There is a first draft available created by @dingo-d, which can be iterated on #239)
  • Squiz.Classes.ClassDeclaration
  • Squiz.Classes.ClassFileName
  • Squiz.Classes.ValidClassName
  • Squiz.Commenting.BlockComment
  • Squiz.Commenting.ClassComment
  • Squiz.Commenting.ClosingDeclarationComment
  • Squiz.Commenting.EmptyCatchComment
  • Squiz.Commenting.FileComment
  • Squiz.Commenting.FunctionComment
  • Squiz.Commenting.InlineComment
  • Squiz.Commenting.LongConditionClosingComment
  • Squiz.Commenting.PostStatementComment
  • Squiz.Commenting.VariableComment
  • Squiz.ControlStructures.ControlSignature
  • Squiz.ControlStructures.ElseIfDeclaration
  • Squiz.ControlStructures.InlineIfDeclaration
  • Squiz.ControlStructures.SwitchDeclaration
  • Squiz.Files.FileExtension
  • Squiz.Formatting.OperatorBracket
  • Squiz.Functions.FunctionDeclarationArgumentSpacing
  • Squiz.Functions.FunctionDuplicateArgument
  • Squiz.Functions.FunctionDeclaration
  • Squiz.Functions.GlobalFunction
  • Squiz.Functions.MultiLineFunctionDeclaration
  • Squiz.NamingConventions.ValidFunctionName
  • Squiz.NamingConventions.ValidVariableName
  • Squiz.Objects.ObjectInstantiation
  • Squiz.Operators.ComparisonOperatorUsage
  • Squiz.Operators.IncrementDecrementUsage
  • Squiz.Operators.ValidLogicalOperators
  • Squiz.PHP.CommentedOutCode
  • Squiz.PHP.DisallowBooleanStatement
  • Squiz.PHP.DisallowComparisonAssignment
  • Squiz.PHP.DisallowInlineIf
  • Squiz.PHP.DisallowMultipleAssignments
  • Squiz.PHP.DisallowSizeFunctionsInLoops
  • Squiz.PHP.DiscouragedFunctions
  • Squiz.PHP.EmbeddedPhp
  • Squiz.PHP.Eval
  • Squiz.PHP.GlobalKeyword
  • Squiz.PHP.Heredoc
  • Squiz.PHP.InnerFunctions
  • Squiz.PHP.LowercasePHPFunctions
  • Squiz.PHP.NonExecutableCode
  • Squiz.Scope.MemberVarScope
  • Squiz.Scope.MethodScope
  • Squiz.Strings.ConcatenationSpacing
  • Squiz.Strings.DoubleQuoteUsage

Note: a number of sniffs will be removed in v 4.0. Those have been deliberately excluded from the above action list.

Claimed/Work in Progress

  • Generic.Arrays.ArrayIndent - @rodrigoprimo #432
  • Generic.Commenting.DocComment - @rodrigoprimo #247
  • Generic.VersionControl.GitMergeConflict - @rodrigoprimo
  • Squiz.WhiteSpace.ControlStructureSpacing - @jonmcp
  • Squiz.WhiteSpace.FunctionOpeningBraceSpace - @jonmcp
  • Squiz.WhiteSpace.FunctionSpacing - @jonmcp #451
  • Squiz.WhiteSpace.LogicalOperatorSpacing - @jonmcp
  • Squiz.WhiteSpace.OperatorSpacing - @jonmcp

Done

Want to contribute ?

Leave a comment below to claim a sniff you'll be working on.

PRs related to this task should preferably only contain the docs for one sniff each.

Tests: add end-to-end tests for all supported CLI arguments

End to end tests should be introduced in a separate test suite to cover the use of all supported CLI arguments (and some combinations of these).

PHPUnit supports a phpt format to run end to end tests, though there is not much documentation available on writing them (see sebastianbergmann/phpunit-documentation-english#302).
Alternatively, something like the expect could possibly be used.

I've written some tests as a proof of concept and will try to make those publicly available in the near future to serve as an example to expand on.

The end-to-end tests should preferably be run in CI on:

  • Different OSes (Linux, Mac, Windows)
  • A few different PHP versions (high/low supported versions and possible some extra if there are specific issues which need to be tested on specific versions)
  • Using the PHAR file + using a Composer install
  • With a few different extensions enabled/disabled combinations, including PCNTL and gRPC (see #294).
  • With a few different combinations of relevant ini settings (can likely be configured per test)

Squiz/EmbeddedPhp doesn't examine code using short open echo tag

Repost from squizlabs/PHP_CodeSniffer#3705:

Given this code:

<?php   echo $var   ?>

Running the Squiz.PHP.EmbeddedPhp sniff over it results in:

-------------------------------------------------------------------------------------------------------------
FOUND 3 ERRORS AFFECTING 1 LINE
-------------------------------------------------------------------------------------------------------------
 1 | ERROR | [x] Expected 1 space after opening PHP tag; 3 found
   |       |     (Squiz.PHP.EmbeddedPhp.SpacingAfterOpen)
 1 | ERROR | [x] Inline PHP statement must end with a semicolon (Squiz.PHP.EmbeddedPhp.NoSemicolon)
 1 | ERROR | [x] Expected 1 space before closing PHP tag; 3 found
   |       |     (Squiz.PHP.EmbeddedPhp.SpacingBeforeClose)
-------------------------------------------------------------------------------------------------------------
PHPCBF CAN FIX THE 3 MARKED SNIFF VIOLATIONS AUTOMATICALLY
-------------------------------------------------------------------------------------------------------------

... while running the same sniff over the below code doesn't yield any errors:

<?=   $var   ?>

Questions

  1. Should the T_OPEN_TAG_WITH_ECHO token be added to the sniff ?
  2. If so and as the sniff would now start acting on more files, should the error codes for issues found in embedded PHP statements using short open echo tags be different ?

Document release process

Repost from squizlabs/PHP_CodeSniffer#3861:

In a number of projects I'm involved in, I've started adding "release checklists" in an effort to document the steps for releasing a new version and make that knowledge transferable.

Example:

The release process for this repo is currently not documented and I believe it would be helpful to document it.

Aside from the obvious (tag & release on GH), I'm aware of a few additional things which are needed for this repo, but I currently don't have insight into the exact steps involved/the how of these things.

  • Release to PEAR.
  • Make the PHAR files available on a web-accessible URL.

Releasing from PEAR has been dropped in #4.
Other than that, the release process should be documentable.

Feature request: CLI option to clear the results cache

Repost from squizlabs/PHP_CodeSniffer#2993:

While testing #2992, I really missed an option to clear the cache, but allow for it to be set.

The --no-cache option only tells PHPCS to not use the cache for that particular run.

It doesn't clear an existing cache file, or in case of the temp directory being used: clear all existing cache files, as those can accumulate to be quite a large number of files quickly.

Please consider this a feature request for a CLI argument to clear the cache(s) to be added.


`phpcs:enable` can sometimes override `phpcs:ignore`

Duplicated from squizlabs/PHP_CodeSniffer#3889 (and updated from later comments)


Describe the bug

phpcs:enable can sometimes wind up overriding a later phpcs:ignore for the rule. This can particularly happen when multiple phpcs:enable comments are present in the file.

Code sample

<?php

// phpcs:disable PSR12.Operators.OperatorSpacing.NoSpaceBefore
// phpcs:disable PSR12.Operators.OperatorSpacing.NoSpaceAfter
$x=1;
// phpcs:enable PSR12.Operators.OperatorSpacing.NoSpaceAfter
// phpcs:enable PSR12.Operators.OperatorSpacing.NoSpaceBefore

$x= 2; // phpcs:ignore PSR12.Operators.OperatorSpacing.NoSpaceBefore
<?php

// phpcs:disable Generic
// phpcs:enable Generic.PHP
// phpcs:disable Generic.PHP.LowerCaseConstant
$var = TRUE;

Custom ruleset

N/A

To reproduce

Steps to reproduce the behavior:

  1. Create a files called test1.php and test2.php with the code samples above.
  2. Run phpcs -s --standard=PSR12 test1.php test2.php
  3. See error message displayed
FILE: /tmp/test/test1.php
---------------------------------------------------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
---------------------------------------------------------------------------------------------------------------
 9 | ERROR | [x] Expected at least 1 space before "="; 0 found
   |       |     (PSR12.Operators.OperatorSpacing.NoSpaceBefore)
---------------------------------------------------------------------------------------------------------------
PHPCBF CAN FIX THE 1 MARKED SNIFF VIOLATIONS AUTOMATICALLY
---------------------------------------------------------------------------------------------------------------


FILE: /tmp/test/test2.php
--------------------------------------------------------------------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
--------------------------------------------------------------------------------------------------------------------------------
 6 | ERROR | [x] TRUE, FALSE and NULL must be lowercase; expected "true" but found "TRUE"
   |       |     (Generic.PHP.LowerCaseConstant.Found)
--------------------------------------------------------------------------------------------------------------------------------
PHPCBF CAN FIX THE 1 MARKED SNIFF VIOLATIONS AUTOMATICALLY
--------------------------------------------------------------------------------------------------------------------------------

Expected behavior

The error on test1.php line 9 should have been ignored due to the phpcs:ignore comment on that line.

The error on test2.php line 6 should have been ignored due to the specific rule having been disabled.

Versions (please complete the following information)

Operating System Debian sid
PHP version 8.2.12
PHP_CodeSniffer version 3.7.2, master
Standard PSR12
Install type Composer local

Additional context

It seems that in this situation it's setting $ignoring['.except'][...], which overrides phpcs:ignore.

Please confirm:

  • I have searched the issue list and am not opening a duplicate issue.
  • I confirm that this bug is a bug in PHP_CodeSniffer and not in one of the external standards.
  • I have verified the issue still exists in the master branch of PHP_CodeSniffer.

Feature suggestion: allow for "standards" to be hidden

Repost from squizlabs/PHP_CodeSniffer#2760:

Use-case: sniffs in generic sniff collections - like the Generic set in PHPCS - can be freely used by other standards, but shouldn't ever be included in a custom ruleset like <rule ref="Generic"/> as they may (and often will, like Generic) contain sniffs which contradict each other.

For the build-in Generic standard, PHPCS makes a hard-coded exception and doesn't list it when someone calls up phpcs -i.

https://github.com/squizlabs/PHP_CodeSniffer/blob/120c713213260a38988ac17816058ba3686f4e8f/src/Util/Standards.php#L107-L110

https://github.com/squizlabs/PHP_CodeSniffer/blob/120c713213260a38988ac17816058ba3686f4e8f/src/Util/Standards.php#L197-L200

I'd like to propose making that a feature available to external standards as well.
For one, I imagine the SlevomatCodingStandard could use it, but I see some more use-cases in the future.

I envision this can most easily be done by adding a new attribute to the ruleset element in the xsd and adjusting the code for the -i option to respect the setting found there.

Something like list with the default being true.

<ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    name="Generic"
    list="false"
    xsi:noNamespaceSchemaLocation="../../../phpcs.xsd">

Implementation-wise, AFAICS this will be easiest to implement via the Standards::getInstalledStandardDetails() method and the Standards::getInstalledStandards() should then probably defer to that method instead of it being a stand-alone method.

Opinions ?


Thinking about this issue now, I have a feeling end-users might get confused if they don't see an expected standard when running phpcs -i, so hiding the standard(s) may not be the right action.

Possibly listing them as a separate category "Additional non-standard rulesets" or something like that ? (including Generic)
Or listing them with an * next to their name or something, might be better.

I'd love to see more input from end-users about what would be most helpful to them.


4.0 | Make sure everything that was merged/included in the 3.x branch is also included in 4.0 / Rebase the branch

The 4.0 branch was branched off in January 2020 (just after the 3.5.4 release) and aside from 4.x specific changes, (nearly) all changes which have gone into the 3.x branch since then, should also be included in the branch.
Additionally, changes which have been merged up into the 4.x branch should, at times, have been updated/adjusted to comply with changed functionality in the 4.x branch.

To verify this is difficult with the branches as they currently are, especially as 4.0 has been such a long-running branch already.

I'm contemplating how to verify this properly and my current line of thinking is to rebase (and partially recreate) the 4.x branch on top of the current dev-master branch.

While I don't expect this will cause significant problems for contributors and/or external standards, it would mean that:

  • Contributors who have a local 4.0 branch will need to reset that branch after the rebase.
  • Contributors who have local/public branches created for the 4.0 branch, will need to rebase those branches.

I'm opening this issue to raise awareness about this intention and to allow for people to raise concerns about this plan.
If you have any (concerns), please speak up and leave a comment.

Time-line wise, I expect to execute this change some time in the new year, in two or three months time.

Tests: parse error tests for sniffs should be in their own file

Basic premise

Sniffs at times need to gracefully handle parse errors in the code under scan and often contain defensive coding for this.

This code should be covered by tests.

Current situation

A sniff may have multiple blocks of logic to handle parse errors, but oftentimes only has one test case file.

This is not so much of a problem with compile errors, but for parse errors, it generally means that the test case file only contains one test with a parse error at the end of the test case file, which also means that if the sniff contains more than one block of logic related to parse errors, only one of those code blocks is covered by tests.

This also makes it more fiddly for (new) contributors to know where to add a test when they update a sniff as they need to be careful to make sure that their new test is added above the parse error test, instead of at the very end of the file.

Lastly, if the parse error would be one where the sniff would throw an error, it also means that the line numbers for the test expectations need to be updated every time an extra test is added (above the parse error test).

Desired situation

  • Parse error related tests should be in their own test case file.
  • Tests files containing a parse error test should only contain that test and no other and be clearly annotated as a parse error test.

Example of tests where this is done correctly

The tests for the Generic.ControlStructures.InlineControlStructure sniff: https://github.com/PHPCSStandards/PHP_CodeSniffer/tree/master/src/Standards/Generic/Tests/ControlStructures

  • The InlineControlStructureUnitTest.1.inc does not contain a parse error test at the end.
  • There are multiple additional test case files which each contain one test for a specific parse error the sniff handles. Each of those tests is also clearly annotated as being a parse error test.

Note: this does not mean that all parse error related code blocks in the sniff are comprehensively tested (yet). This is just a good example of how the tests for parse errors should be structured.

Example of a test where this is not done correctly

Future scope

It would be good to prevent accidental parse errors from creeping into the test case files as in that case, the test may not sufficient safeguard the working of the sniff.

Once all parse error related tests are in their own files, a linting task could be added to CI to run over the non-parse error test case files to safeguard this.

Tasks

Typical ways to approach this task:

  • Look for tests in the test suites for the sniffs which are already annotated as parse error/live coding tests and check if the test is in its own file. If not, fix it.
  • Run a linter over test case files to see if they contain parse error tests.
    When parse errors are found,:
    • When the test is not marked as a parse error test, it may be an accidental parse error, which should be fixed.
    • Or it may be an intentional parse error missing the annotation, in which case the test should be moved to its own file.
    • Git blame can often help to determine whether a parse error in the test case file is intentional or accidental.

Some practical guidelines:

  1. If there is only one test case file for the sniff, rename the file from SniffNameUnitTest.inc to SniffNameUnitTest.1.inc (same for potential .fixed test case files) and update the SniffNameUnitTest.php file to expect the $testFile parameter and use a switch statement to return the right array.
    Commit this in a separate commit. That way the chance that git will recognize this as a renamed file will be largest, which means history checks for the test case file won't be broken.
  2. Move the parse error test to a new SniffNameUnitTest.2.inc file, if applicable do the same for the .fixed file, and if necessary, update the expectations in the SniffNameUnitTest.php file.

This check should be executed for the complete all sniff tests.

PRs related to this task should preferably only touch the tests for one sniff per PR.

Refactor/modernize test suite setup

Repost from squizlabs/PHP_CodeSniffer#3395:

As I've been seeing new issues popping up elsewhere with some of the recent changes in PHP 8.1, I had a look at the latest test run for this repo and as I feared, the tests break on PHP 8.1 due to PHPUnit 7.5 being used.

See: https://github.com/squizlabs/PHP_CodeSniffer/runs/3118862021?check_suite_focus=true

As PHPUnit 7.5 is no longer supported, this will not be fixed on the PHPUnit side of things.

I think a refactor of the test suite setup is in order to allow it to be compatible with a wider range of PHPUnit versions, preferably without BC-break in the setup as quite a lot of external standards use the PHPCS native abstract test classes for their tests as well.


Initial part solved via squizlabs/PHP_CodeSniffer#3400


While the PHP 8.1 issues have been solved by now, I'm going to leave this issue open, as IMO a refactor of the test suite setup may still be a good idea and make the setup more sustainable in the long run.

The setup as is, with the AllTests, the dynamic test suite creation etc seems to be based on a really old PHPUnit version and while it still works, the framework as-is, is creaking more and more with each new PHP version.


As things are at this time, if PHPCS wants to allow running tests on PHPUnit 10.x (which it should), at least two things needs to happen (maybe more):

  1. Rename abstract base test cases. Those classes are no longer allowed to have the Test suffix.
    I'd recommend renaming the suffix from UnitTest to TestCase.
    See: sebastianbergmann/phpunit#5132
  2. Changing the test suite set up to remove the use of the old style set up with AllTests.php and AllSniffs.php containing a static suite method, which is no longer supported.

    PHPUnit no longer invokes a static method named suite on a class that is declared in a file that is passed as an argument to the CLI test runner
    Ref: https://github.com/sebastianbergmann/phpunit/blob/10.0.19/ChangeLog-10.0.md#1000---2023-02-03 (Changed section)
    Also related:

If losing the line created via the bootstrap printPHPCodeSnifferTestOutput() method would not be considered a big deal, changing things round to remove the AllTests and AllSniffs files and letting PHPUnit self-discover the tests in a test suite would probably work.
Includes and setting of globals and constants should probably be moved to the test bootstrap.php file.

The printPHPCodeSnifferTestOutput() output could possibly still be generated by creating a custom PHPUnit Extension (formally TestListener).

As fixing this would mean breaking changes for any external standard which uses the PHPCS base test classes for their own test suites, I'd recommend for these changes to be made in PHPCS 4.0.0 and no later than that.

Unnecessary line wrapping with `-s`

Describe the bug

This is a re-creation of squizlabs/PHP_CodeSniffer#3924:

When using -s along with a large --report-width, some lines are still wrapped despite being much shorter than the selected width.

Code sample

<?php

$x=1;

Custom ruleset

N/A

To reproduce

Steps to reproduce the behavior:

  1. Create a file called test.php with the code sample above.
  2. Run phpcs -s --report-width=100000 --standard=PSR12 test.php
  3. See output displayed
FILE: /tmp/test/test.php
---------------------------------------------------------------------------------------------------------------
FOUND 2 ERRORS AFFECTING 1 LINE
---------------------------------------------------------------------------------------------------------------
 3 | ERROR | [x] Expected at least 1 space before "="; 0 found
   |       |     (PSR12.Operators.OperatorSpacing.NoSpaceBefore)
 3 | ERROR | [x] Expected at least 1 space after "="; 0 found
   |       |     (PSR12.Operators.OperatorSpacing.NoSpaceAfter)
---------------------------------------------------------------------------------------------------------------
PHPCBF CAN FIX THE 2 MARKED SNIFF VIOLATIONS AUTOMATICALLY
---------------------------------------------------------------------------------------------------------------

Expected behavior

FILE: /tmp/test/test.php
---------------------------------------------------------------------------------------------------------------
FOUND 2 ERRORS AFFECTING 1 LINE
---------------------------------------------------------------------------------------------------------------
 3 | ERROR | [x] Expected at least 1 space before "="; 0 found (PSR12.Operators.OperatorSpacing.NoSpaceBefore)
 3 | ERROR | [x] Expected at least 1 space after "="; 0 found (PSR12.Operators.OperatorSpacing.NoSpaceAfter)
---------------------------------------------------------------------------------------------------------------
PHPCBF CAN FIX THE 2 MARKED SNIFF VIOLATIONS AUTOMATICALLY
---------------------------------------------------------------------------------------------------------------

Versions (please complete the following information)

Operating System Debian sid
PHP version 8.2.12
PHP_CodeSniffer version 3.7.2, master
Standard PSR12
Install type Composer local

Additional context

The problem seems to be that the four non-displaying characters (\033[0m) added at

$msgLine .= "\033[0m".' ('.$error['source'].')';
are not accounted for when calculating $maxErrorLength at
$length += (strlen($error['source']) + 3);
Or, alternatively, that those four characters aren't being ignored by PHP's wordwrap().

The simple fix would be to add 4 more at line 69, with the downsides that the lines of dashes would be longer than necessary and a --report-width that's just barely long enough (e.g. 111 for this example) would still unnecessarily wrap.

A more complex fix might be to wordwrap() only the message, and then manually calculate the length of the last line to decide whether to append the source directly or to append it as a new line.

Please confirm:

  • I have searched the issue list and am not opening a duplicate issue.
  • I confirm that this bug is a bug in PHP_CodeSniffer and not in one of the external standards.
  • I have verified the issue still exists in the master branch of PHP_CodeSniffer

Make the PHAR "website" a little more fancy

The PHAR files get published with each release on the releases page, but they also are available via a permanent address: https://phars.phpcodesniffer.com/ with historic phars available for download in the https://phars.phpcodesniffer.com/phars/ subdirectory.

This subdomain is managed via the gh-pages branch in this repo and is currently very plain.

It would be nice to make the "homepage" look a little more fancy/professional than the current quick & dirty:
image

It would also be nice if the phars subdirectory would contain an (automated) listing of all historic PHAR files available (instead of the 404 it currently displays).

Auto fix of Squiz.Formatting.OperatorBracket.MissingBrackets is incorrect when working with ?? operator

Duplicated from here, as requested.

Describe the bug

The autofixer fixes the Squiz.Formatting.OperatorBracket.MissingBrackets in a specific case with the ?? operator by malrforming the existing logic:

Instead of bracketing the whole statement, it brackets part of it, thus changing the behavior of the affecting line

Code sample

'test' => $foo->prop ?? 'test_' . $bar,

becomes

'test' => ($foo->prop ?? 'test_') . $bar,

although it should have become

'test' => ($foo->prop ?? 'test_' . $bar),

if I'm not completely mistaken

To reproduce

Steps to reproduce the behavior:

  1. Create a file called test.php with the code sample above
  2. Run the autofixer
  3. Verify that you get changed behavior in the changed code.

Versions (please complete the following information)

Operating System Windows 10]
PHP version 7.4.3
PHP_CodeSniffer version [e.g., 3.5.5, master]
Standard Squiz]

Additional context

Add any other context about the problem here.

Please confirm:

  • I have searched the issue list and am not opening a duplicate issue.
  • I confirm that this bug is a bug in PHP_CodeSniffer and not in one of the external standards.
  • I have verified the issue still exists in the master branch of PHP_CodeSniffer.

Feature request: Array property extending doesn't work when property has default value

Repost from squizlabs/PHP_CodeSniffer#2228:

PR squizlabs/PHP_CodeSniffer#2154 added support for array properties being extended, however it appears that this doesn't work when an array property already has a default value set.

If we take the original example of the Generic.PHP.ForbiddenFunctions sniff, it all works correctly if you overrule the forbiddenFunctions property in a standard and then extend it from a project-based ruleset.

However, if you want to extend the default values of the forbiddenFunctions property:

public $forbiddenFunctions = [
     'sizeof' => 'count',
     'delete' => 'unset',
];

either via a standard or a project ruleset:

<rule ref="Generic.PHP.ForbiddenFunctions">
	<properties>
		<property name="forbiddenFunctions" type="array" extend="true">
			<element key="foo" value="fixedFoo"/>
			<element key="bar" value="fixedBar"/>
		</property>
	</properties>
</rule>

You end up with:

public $forbiddenFunctions = [
    'foo' => 'fixedFoo',
    'bar' => 'fixedBar',
];

instead of the expected:

public $forbiddenFunctions = [
    'sizeof' => 'count',
    'delete' => 'unset',
    'foo' => 'fixedFoo',
    'bar' => 'fixedBar',
];

Related squizlabs/PHP_CodeSniffer#2153


Feature Request: Per-directory configuration

Is your feature request related to a problem?

It's difficult to write and maintain XML configuration rules to apply different subdirectories, as the existing configuration file syntax is oriented towards specifying paths that apply to rules rather than rules that apply to paths.

See also squizlabs/PHP_CodeSniffer#2551

Describe the solution you'd like

Per-directory configuration files would be nice. Conceptually there are at least two ways this might work: for example, if you have a file at subdir/.phpcs.dir.xml then for files in that directory phpcs would

  1. act as if it had been run as phpcs --standard=.phpcs.xml.dist,subdir/.phpcs.dir.xml, loading the subdirectory ruleset as a peer of the parent's, or
  2. use subdir/.phpcs.dir.xml as the ruleset, but treat that file as if it had <rule ref="../.phpcs.xml.dist" /> at the start.

Additional context (optional)

We've been using a fork of phpcs that enables this in our monorepo at https://github.com/Automattic/jetpack since December 2021 and it has worked out very well for us despite some caveats.

The important caveats with the version in the fork are:

  • The fork itself is pretty minimal, as in the old repo it seemed like 4.0 was never going to happen. Basically the fork just enables filters to return a PHP_CodeSniffer\File instance instead of a filename. Then a custom filter returns File instances that have different values for ->ruleset and ->config as necessary to reflect the per-dir config files.
  • Since the PHP_CodeSniffer\Config class is half-static, <config> doesn't work well at a per-directory level.
    • Various other directives like <ini> and <arg> and <autoload> also don't work at a per-directory level, but those are much easier to classify as "global" and therefore say they shouldn't work per-directory.
  • Since our fork takes the --standard=.phpcs.xml.dist,subdir/.phpcs.dir.xml approach rather than the implicit-<rule ref="../.phpcs.xml.dist" /> approach (because the latter is a lot harder to do from a filter), <exclude name="Standard.Category.Rule" /> doesn't work to exclude a rule that had been enabled in a parent directory. Since <exclude name="Standard.Category.Rule"><severity>0</severity></exclude> does still work, that hasn't been that much of a problem.

Since a 4.0 release seems imminent in the new repo, I wonder whether I might do better to do a more invasive PR than we had done in squizlabs/PHP_CodeSniffer#3378. The main breaking change a more invasive PR would do would be to change methods like Config::getConfigData() to be non-static, which would affect sniffs that use Config. Probably they'd have to access the instance via $phpcsFile->config instead.

  • I intend to create a pull request to implement this feature.

4.0 | Make isset, unset and empty parenthesis owners

Repost from squizlabs/PHP_CodeSniffer#3118:

I was just wondering why isset(), unset() and empty() - all language constructs which require parentheses - are not considered parentheses owners.

Would it make sense to change that ? Should be a relatively easy change to make as far as I can see.

Happy to make the changes if there is interest.


[Edit]: Might be useful to include exit(), die() and eval() as well, though these three don't require parentheses, but are "owners" when the parentheses are present.


See the original post for some pointers about the implementation.

After installation still informs version from SquizLabs

Describe the bug

I've executed the new installation in my project, php-toolbox with the instructions for this source, using Composer. However, when I run phpcs --version, the output still prints the SquizLabs message, as below:

image

~/.composer/vendor # which phpcs
/usr/local/bin/phpcs
~/.composer/vendor # phpcs --version
PHP_CodeSniffer version 3.7.2 (stable) by Squiz (http://www.squiz.net)
~/.composer/vendor # ls -lah /root/.composer/vendor/ | grep phpcsstandards
drwxr-xr-x    3 root     root        4.0K Dec  1 20:47 phpcsstandards
~/.composer/vendor # ls -lah /root/.composer/vendor/phpcsstandards/
total 12K
drwxr-xr-x    3 root     root        4.0K Dec  1 20:47 .
drwxr-xr-x   48 root     root        4.0K Dec  1 20:47 ..
drwxr-xr-x    5 root     root        4.0K Feb 22  2023 php_codesniffer

PS: If there is any path to fix this, I'm able to fork + PR 😉

Code sample

N/A

Custom ruleset

N/A

To reproduce

Steps to reproduce the behavior:

  1. Install phpcs with the command below:
composer global require phpcsstandards/php_codesniffer
  1. Run phpcs --version.
  2. See output.
~/.composer/vendor # phpcs --version
PHP_CodeSniffer version 3.7.2 (stable) by Squiz (http://www.squiz.net)

Expected behavior

The output should write a message referring to this project.

Versions (please complete the following information)

Operating System Linux Alpine 3.18
PHP version 7.4, 8.0, 8.1, 8.2, 8.3
PHP_CodeSniffer version 3.7.2
Standard N/A
Install type Composer (global)

Additional context

N/A

Please confirm:

  • I have searched the issue list and am not opening a duplicate issue.
  • I confirm that this bug is a bug in PHP_CodeSniffer and not in one of the external standards.
  • I have verified the issue still exists in the master branch of PHP_CodeSniffer.

Feature suggestion: Improve information available about installed standards

Repost from squizlabs/PHP_CodeSniffer#2600:

(I seem to remember seeing a discussion about something like this before, but can't find it anymore, so hoping I'm not opening a duplicate issue)

At this moment, there is the --version option to show the version of PHPCS itself, the -i option to show which (external) standards are installed and the --config-show option which provides information on the configuration used.

# phpcs --version
PHP_CodeSniffer version 3.5.0 (stable) by Squiz (http://www.squiz.net)

# phpcs -i
The installed coding standards are MySource, PEAR, PSR1, PSR12, PSR2, Squiz, Zend, PHPCompatibility, Debug, PHPCSDev, WordPress, WordPress-Core, WordPress-Docs, WordPress-Extra, WPThemeReview, Joomla and Symfony

# phpcs --config-show
Using config file: /path/to/PHP_CodeSniffer/CodeSniffer.conf                                                                                     
                                                                                                                                                            
installed_paths: /path/to/PHPCompatibility,/path/to/PHPCSDevTools,/path/to/WordPress,/path/to/WPThemeReview,/path/to/Joomla-coding-standards,/path/to/Symfony-coding-standard
report_width:    90                                                                                                                                         

I believe it would be helpful if there was a command-line option available which would combine some of this information.

For this to work as I envision, external standards would need to be allowed to pass their version number on to PHPCS through the XML ruleset.

Something along the lines of:

<ruleset
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    name="PHPCSDev"
    namespace="PHPCSStandards\PHPCSDev"
    version="1.0.0"
    xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/squizlabs/PHP_CodeSniffer/master/phpcs.xsd">
    ...
</ruleset>

This would require a change to the phpcs.xsd file along the lines of adding the below to the <xs:element name="ruleset"> block:

            <xs:attribute name="version" type="xs:string"></xs:attribute>

Secondly, either one of the above mentioned command-line options would need to be adjusted or a new one should be introduced, let's call it --list-standards for now.

I imagine the output could then look something like this:

# phpcs --list-standards
PHP_CodeSniffer version 3.5.0 (stable) by Squiz (http://www.squiz.net)

Standards        | Version   | Installed path
---------------------------------------------------------------
MySource         | 3.5.0     | N/A (build-in)
PEAR             | 3.5.0     | N/A (build-in)
PSR1             | 3.5.0     | N/A (build-in)
PSR2             | 3.5.0     | N/A (build-in)
PSR12            | 3.5.0     | N/A (build-in)
Squiz            | 3.5.0     | N/A (build-in)
Zend             | 3.5.0     | N/A (build-in)
Debug            | 1.0.0     | /path/to/PHPCSDevTools
Joomla           | 2.0.0-rc3 | /path/to/Joomla-coding-standards
PHPCompatibility | 9.3.0     | /path/to/PHPCompatibility
PHPCSDev         | 1.0.0     | /path/to/PHPCSDevTools
Symfony          | 3.9.0     | /path/to/Symfony-coding-standard
WordPress        | 2.1.1     | /path/to/WordPress
WordPress-Core   | 2.1.1     | /path/to/WordPress
WordPress-Docs   | 2.1.1     | /path/to/WordPress
WordPress-Extra  | 2.1.1     | /path/to/WordPress
WPThemeReview    | 0.2.0     | /path/to/WPThemeReview

For standards which do not (yet) supply the version number via the ruleset.xml file, it could be tried to retrieve the version number via a composer --show in case of a Composer based install.

For non-Composer based installs, the version could either be left empty of be listed as Unknown.

Also take note of the ordering of the list: build-in standards first and then external standards in alphabetic order using natsort.

Opinions ?


See the original issue for additional considerations.

Short list vs short array

Repost from squizlabs/PHP_CodeSniffer#1984:

PHP 7.1 introduced the "short list syntax", i.e. using the short array syntax instead of calling list().
Ref: http://php.net/manual/en/migration71.new-features.php#migration71.new-features.symmetric-array-destructuring

Now I can imagine that in some situations it would be useful to be able to make the distinction whether something is used as a short list vs a short array.

There are two ways this can be done:

  1. Introduce T_OPEN_SHORT_LIST/T_CLOSE_SHORT_LIST tokens and let the Tokenizer handle it.
    The downside of this first solution is that in a lot of cases - especially when sniffing for code style -, I imagine that short list/array should be treated the same, so those sniff would then need to add two additional tokens to sniff for.
  2. Introduce a utility function which can make the distinction and can be called by select sniffs if/when needed.

For the PHPCompatibility standard, I have already created the utility function (solution 2), including extensive unit tests for it.
See: PHPCompatibility/PHPCompatibility#635

If there would be interest in having such a utility function in PHPCS itself, I'd be happy to pull it here.


See the original issue for an extensive discussion on the topic.

My current line of thinking is to add a nested_brackets index to the token array. This would allow for sniffs to figure out if they are dealing with a (nested) short list or a short array much more easily.

I'm tentatively earmarking this ticket for 4.0, but it may well be moved to a later release.

Inconsistent behaviour findPrevious() vs findNext()

Repost from squizlabs/PHP_CodeSniffer#1319:

I've been tripped up by this a number of times already, so putting this out here for consideration.

If the $start and $end token positions you pass to findPrevious() are the same, the function will work as expected. However, the same can not be said about the findNext() method as in that case it will always return false.

This is caused by the findPrevious() method treating the end position as inclusive for ($i = $start; $i >= $end; $i--), while the findNext() method treats it as exclusive for ($i = $start; $i < $end; $i++).

There are two possible solutions for this:

  • Either check for $start and $end being the same and adding 1 to the $end in that case before entering the loop. This will lead to the least difference with current behaviour. - PR #1320
  • Or make the loop in findNext() inclusive as well. This might lead to more breakage, but would make the functions more consistent in use. - PR #1321

See the original issue for an extensive discussion on the BC breaks involved and possible approaches.

My current line of thinking is on the cautious side: implement option 1 for PHPCS 4.0 and option 2 for PHPCS 5.0.

The Future of PHP_CodeSniffer

Repost from squizlabs/PHP_CodeSniffer#3932:

TL;DR: This repo is being abandoned. The project continues in the PHPCSStandards organisation.


Okay, it's time.

About seven months ago, I was given commit access to this repository. At that time, @gsherwood and me had a call and the agreement was that we'd work together through the back log and get 3.8.0 released, which would give me the chance to get insight into his process, the release process and to verify that we were aligned in vision for the future for the repository.
This agreement included, at my insistence, the provision that I would not merge my own PRs and that Greg would preferably also work via PRs for his contributions.

This started off well and I made a plan with a priority-list for which PRs to merge in which order, made lists with on-going and future projects etc and we had two calls in May this year, but I think most of you who have followed the repo closely will have noticed that it ended there.

I'd been trying to get a response, any kind of response, from Greg since beginning of June and have been sending pings at regular intervals with little effect, aside from one short "sorry, no sight on availability" in July.

A few of weeks ago, I have finally received a, just as short, response which basically said that Greg will abandon the project.

image

I very much respect Greg's decision and would like to thank him for all his tireless work and the years and years he has maintained this package for the benefit of the wider PHP community. He is a true open source hero and I wish him all the best.

Having said that, this is where we are now:

  • I only have commit, not admin access to the repo.
  • I don't have insight in the release process nor access to PEAR or Packagist for this repo.

With that in mind, I asked Greg to transfer the repository to the PHPCSStandards organisation, which would give me full control.
I also asked him to give me access to Packagist and PEAR.
This would allow for keeping the package in PEAR and Packagist under its current name and should make for a smooth transition for end-users.

Unfortunately, Greg came back to me a week later and conveyed that the Squizlabs company has declined to transfer the repository stating "code ownership" as the reason.

Well, so be it. 🤷

I have now forked the repo to the PHPCSStandards organisation, and spend some time to get it up & running properly and I have registered the repo under the name phpcsstandards/php_codesniffer on Packagist.
Update: The Composer/Packagist name will stay the same.

This is less than ideal as all of the 200.000+ packages which have a dependency on PHP_CodeSniffer will need to update their workflow/composer.json/PHIVE etc.
It means losing all open PRs (with the exception of my own, which I've recreated). It means losing all issues, having to recreate the wiki etc etc.
And even when this repo will be officially marked as abandoned with the PHPCSStandards version marked as its replacement, it still means that the majority of users, who don't watch the repo, will be left to their own devices to figure this out.

So here we are.

For the time being (for as long as I am the sole maintainer), I will merge my own PRs and I will work on getting 3.8.0 released as soon as possible.
As I don't have access to PEAR, nor insight in how to release to PEAR, it will mean dropping support for installations via PEAR straight away. (note: this does not affect the PEAR sniffs)
Support for installation via Composer, PHIVE, PHAR downloads and git clones will continue, though will all undergo name/address changes.

Note: I would recommend waiting to make the switch until the 3.8.0 release has been tagged. Watch releases on the new repo to automatically get notified of this. The changelog will contain the relevant information for making the switch.

It also means that version 4.0 will be released sooner rather than later and that I will automate as much as possible of the release process to allow for more rapid releases.

Going forward, there are plenty of things I would like to improve, both to enhance the end-user experience, as well as to enhance the dev experience for maintainers of external standards. I also have a list of things in mind to try and make the repo more maintainable and make contributing more straight forward.

I have far more ideas than I have time, so I will need help and more importantly, the project will need significant funding, as the amount of work I see ahead of me would leave very little time for paid work, especially considering I also maintain a fair number of the external standards build on top of PHP_CodeSniffer.

I am posting this here in the spirit of openness and I am hopeful that you all will support me in this, both with quality contributions as well as by getting your employers/all those companies which use PHP_CodeSniffer to fund continued maintenance of the project.

Once the dust settles, I will announce more detailed plans for the future and a roadmap for future releases.

In the mean time, please bear with me. I currently still have quite a few other outstanding commitments, so it will take some time before I can free myself up sufficiently, but the repo is open for issues and PRs.

Please note: funding for this project is not a suggestion, but a requirement to safeguard the future of this project and allow for growing the maintainer pool. Without funding, I will not be able to dedicate the time needed to the project, both to move it forward, as well as to coach others to become co-maintainers.
If you want to help, here are channel through which this project can receive funds:

If you support me in this, you can indicate this via a 👍 and by getting companies using PHP_CodeSniffer to start funding the project.

If you have any concerns about all this, please raise them by leaving a comment.

And if you have suggestions on how to make the switch-over experience smoother for end-users, please open an issue in the new repo.

Other than that, please join me in thanking @gsherwood for all the years he's kept this project going!

Oh and give @PHP_CodeSniffer on X or @phpcs on Mastodon a follow if you'd like to stay informed.

P.S.: In the interest of transparency, I have so far only merged maintenance related PRs in the new repo. Now this announcement is out, I will start merging functional PRs over the next few days or so.

Feature suggestion: --validate to check ruleset against XSD

Repost from squizlabs/PHP_CodeSniffer#2188:

PR #1433 added an XML schema file to the repo and while people can use it with external tools to validate their custom rulesets/external standards, I think it could be a nice feature to offer ruleset validation against the XSD file from within PHPCS itself.

I'm thinking a --validate command line option.

  • When called like phpcs --validate=filename.xml it would validate that specific file.
  • When called like phpcs --validate=*/Standards/*/ruleset.xml it would validate all files which match the pattern.
  • When called without a value, like phpcs --validate, it would look for an [.]phpcs.xml[.dist] file in the same way PHPCS does for a normal run and validate such a file if found.
  • When called in combination with other command line options, like for a normal run, it would validate the ruleset(s) and then continue to the normal PHPCS run, providing the ruleset(s) are valid.

Validation could be done using the XMLReader PHP extension which is shipped with PHP by default and enabled by default since PHP 5.1.2.
There are caveats regarding whether libxml is compiled with PHP with schema support, but in case it's not, I suppose an error message could be thrown saying so.

While the initial implementation I'm proposing would be a command-line option, I imagine that ruleset validation could possibly become a standard part of the ruleset processing as of PHPCS 4.0.

Opinions ?

Inspired by:

  • PHPUnit validating the phpunit.xml file before each run since PHPUnit 7.2 - see sebastianbergmann/phpunit#3066.
  • Issue #2151.
  • Questions I've seen (elsewhere) about the new array format.
  • Ruleset errors I've made myself 😜

Related to and could partially replace #2187.


PSR-PER 2.0.0 has been released

Repost from squizlabs/PHP_CodeSniffer#3793:

PSR-PER is an evolving standard which builds onto PSR-12.

The first "release" (= updated standards publication) since the fork of PSR-12 has just been published.

I'm opening this ticket to allow for a discussion on if and if so, how to handle these evolving standards in PHPCS.

Refs:


@kenguest asked:

Is there anything that can be done to help nudge this along?

Also, can I just note that the PER for Coding Standards shouldn't be referred to as a PSR - it is PER CS 2.0 :-)


I replied:

@kenguest Well, aside from the decision which still needs to be taken about this, it might be good to create an action list of the differences between PSR-12 and PSR-PER ?

For each difference, it will need to be determined whether there is an existing sniff which could handle this (possibly with a public property setting) or whether a new sniff is needed.

Another thing to have a good think about would be how to handle versioning, as without some form of versioning, a PSR-PER ruleset would be a moving target which could randomly start failing CI builds due to new rules being introduced (and being sniffed for).


@kenguest replied:

@jrfnl I'm working on a list of changes between the two standards, then an action list.
PER-CS is at version 2 at the moment, and there will be distinct version numbers so it should just be a case of having one set of sniffs called PERCS200 (for v2.0.0) and so on.


My current line of thinking on this is as follows:

  • I agree with @kenguest that each PER version should have its own ruleset, like PER-200, to prevent it from becoming a moving target failing builds at random.
    Each ruleset can include the previous version and build on top of that.
  • For those repos who always want to use the latest version, there should also be a PER-latest, which would include the ruleset for the current version and would need to be updated each time a new version is added.
  • As there could be a lot of PER versions, adding these rulesets to the main PHPCS repo may be a bit unwieldy, so I'm thinking a separate repo in this organisation called PSR-PER.
  • Sniffs needed in the PER rulesets should still be pulled to the main PHPCS repo. The PSR-PER repo would only contain rulesets, not sniffs.

Generic/IncrementDecrementSpacing: handle (yet) more situations

Is your feature request related to a problem?

Quoting from a discussion in squizlabs/PHP_CodeSniffer#3626:

For pre-increment, I can think of a further/future iteration for the sniff - checking whether a pre-increment is used on a static property with a fully qualified classname or namespace relative classname, but that is something I choose not to handle (yet) when I made this change last year. When that change would be added, then, yes, extra tests would be needed for pre-in/decrement.

++\ClassName::$prop;
++Relative\ClassName::$prop;
--namespace\Relative\ClassName::$prop;

The reason I did not make that change (yet) is that this would need a different patch for PHPCS 3.x vs PHPCS 4.x, which would make the merge more complex. Also see squizlabs/PHP_CodeSniffer#3041.

Describe the solution you'd like

Valid (correct spacing):

++\ClassName::$prop;
++Relative\ClassName::$prop;
--namespace\Relative\ClassName::$prop;

Invalid (too much space):

++ \ClassName::$prop;
++    Relative\ClassName::$prop;
-- /*comment*/ namespace\Relative\ClassName::$prop;

Additional context (optional)

Follow up on #46

  • I intend to create a pull request to implement this feature.

Caching on Windows makes CS check incredibly slow

Repost from squizlabs/PHP_CodeSniffer#3558:

Describe the bug

I've done some - not entirely scientific - benchmark checks and am finding that enabling the caching option when on Windows (not sure about other OSes), makes a CS run significantly slower.

For a CS run with a custom ruleset and the following command over 57 files:

phpcs ./inc/ --sniffs=Squiz.Commenting.FunctionComment,Universal.Operators.StrictComparisons,Generic.CodeAnalysis.EmptyPHPStatement,PHPCompatibility.ParameterValues.NewHTMLEntitiesFlagsDefault,PSR12.Files.FileHeader,Squiz.Commenting.InlineComment,WordPress.WP.PostsPerPage

These are the approximate timings I'm seeing:

Checked against Time with cache ON Time without cache OFF (--no-cache)
master Time: 3 mins, 5.61 secs; Memory: 78MB Time: 3.7 secs; Memory: 36MB

Expected behavior
I would expect a little bit of a slow-down the first time PHPCS is run with cache turned on as the cache file needs to be written, but the slow-down I'm seeing now is out of bounds.

Versions (please complete the following information):

  • OS: Windows 10
  • PHP: 8.1.2
  • PHPCS: master, but also checked 3.6.2 tag
  • Standard: custom

Additional context
I haven't done a git bisect yet to figure out if I can pinpoint the slow-down to a specific commit, but felt that the time difference is so huge and on the negative for having caching turned on, this had to be reported forthwith.


Docs: add a list with available external standards to the wiki

Repost from squizlabs/PHP_CodeSniffer#1165:

I was looking for a list of coding standards of well-known open source projects with an eco-system of add-on projects (plugins, themes), such as CakePHP, Drupal, Joomla, Magento, TYPO3, WordPress, preferably with links to the repo and possible link to a documented descriptive standard.

So far I have not been able to find such a list (found quite some standards, but took me hours).

Would it be an idea to add such a list of externally maintained standards which can be used with PHPCS as a wiki page to this repo ?


👉🏻 The thread in the original post contains lots of links to external standards and would be a good starting point.

4.0 | Let T_STATIC be T_STATIC

Repost from squizlabs/PHP_CodeSniffer#3115:

The static keyword in PHP is used for a number of different things:

  • Static properties
  • Static methods
  • Static closures and arrow functions
  • Static variables
  • Late static binding

Now, for all these uses, the token is tokenized as T_STATIC, with one exception: late static binding in combination with the instanceof operator.

This defies the principle of least astonishment as both self and parent in combination with instanceof are tokenized as T_SELF and T_PARENT respectively.

I've been caught out by this a couple of times already and I imagine that others have too, or if they haven't, that sniffs may be throwing false positives/negatives because of it.

It's not completely clear to me why this very specific exception was put in place, but I'd like to propose to remove this exception in PHPCS 4.x and let the static keyword be tokenized as T_STATIC when preceded by instanceof.

Based on a history search, it looks to have been put in place in response to PEAR#19726.
In my opinion, that issue should have been fixed in the sniff code for the Squiz.WhiteSpace.ScopeKeywordSpacing sniff, not in the Tokenizer, same as is done in the sniff with other typical late static binding occurrences.

https://github.com/squizlabs/PHP_CodeSniffer/blob/9cce6859a595b3fa77fc823d9b0d451951dcf9d2/src/Tokenizers/PHP.php#L2086-L2101

Code sample

if ($geometry instanceof static) {
    echo 'foo';
}

static in the above code sample is tokenized as T_STRING, not T_STATIC.


Possible improvements for sniff performance analysis

Repost from squizlabs/PHP_CodeSniffer#3784:

As a sniff author, it is not uncommon to receive reports about sniffs/standards being "slow".

To analyze which sniffs could be the culprit/which sniffs to focus on to improve performance, the -vvv command can be used, which at the very end of the debug logs shows a "SNIFF PROCESSING REPORT" with the sniffs which have been triggered during a run and the time each sniff took, ordered from slowest to fastest sniff.

This information is super-useful, however to get a good impression of the performance of various sniffs, the best way to do so is to run the sniffs/standard against a large number of files, which makes the -vvv output completely unworkable as even for a simple run against 4 files, the output is easily over 60.000 lines, with a test run against 300 files, the output is well over 4 million lines...

The current available verbosity levels and their output are defined as such:

  1. -v: file specific token and line counts with running times
  2. -vv: the info from level 1 + verbose tokeniser output
  3. -vvv: the info from level 1 + 2 + token processing output with sniff running times

Now there are a couple of ways I can think of to improve this situation and I'd like to hear if any of these could/would be acceptable.

  1. Add an extra debugging level between the current 1 (-v) and 2 (-vv) levels, which would contain the information from level 1 + the sniff performance report.
    This would mean that -vv would now show the performance report, while to get the "old" -vv report (+ performance info), one would now need to use -vvv, and the "old" -vvv would become -vvvv.
    While this would be a BC-break, this type of verbosity is generally only ever used by sniff authors/PHPCS tokenizer fix contributors. So considering the very limited public this BC-break would hit, I hope this could be considered acceptable as an enhancement, which could go into a PHPCS 3.x minor.
  2. Add a separate CLI option - outside of the verbosity settings - to allow for the performance information to be printed.
    Maybe using the -r for "(sniff) run time information" ?
    This would avoid the BC-break and would still make the information available in a more workable manner.
  3. Create a Performance Report type, possibly externally hosted, like in PHPCSDevTools.
    To allow for this, some changes would be needed to the File::process() method as it currently only records "time taken by each sniff" to the $this->listenerTimes property if PHP_CODESNIFFER_VERBOSITY > 2, i.e. when the -vvv option is enabled, which would run counter to the problem I'm trying to solve.
    It might also make life easier if, similar to the File::getMetrics() method, there would also be a File::getListenerTimes() method.
    It would still need some work-arounds as $this->listenerTimes is cumulative and only the Report::generateFileReport() method has access to the File object, while the report would need to be generated in the generate() method which doesn't have access to the File object, but that is doable.

In my opinion, option 1 or 2 would be the preferred options as it would also allow standard maintainers to ask performance issue reporters to run the report, even when they can't share access to the (private) code base on which the performance issue was detected.

Having said that, option 3 would still be an improvement over the current situation.

Opinions ?

P.S.: I'd, of course, be happy to make the changes, but would like some direction before spending significant time on this.


The original issue contains a little more discussion on this + screenshots. PR will be moved here soon.

Proposal: treat deprecations/notices/warnings coming from sniffs in a more end-user friendly manner

Repost from squizlabs/PHP_CodeSniffer#3844:

Current situation

As things currently are, when a PHP deprecation/notice/warning/error is received during the scanning of a file, PHPCS turns this into an Internal.Exception and kills the scan of that particular file.

Example 1:

  • A file containing 200 lines of code contains a parse error on line 100.
  • One of the sniffs involved in the scan does not contain enough defensive coding, which leads to a PHP notice for the code on line 100.
  • PHPCS will report the notice as an Internal.exception on line 1 of the file.
  • PHPCS will show the scan results for line 1 - 99 of the file.
  • No errors or warnings are reported for line 100 - 200 of the file.

Example 2:

  • PHP makes a change which causes a deprecation notice in a pre-existing sniff.
  • One of the files being scanned causes the sniff to hit the deprecation notice.
  • PHPCS will report the notice as an Internal.exception on line 1 of the file.
  • PHPCS will show the scan results for the file up to the point the code hit the deprecation notice.
  • No errors or warnings are reported for the rest of the file.

The problem

While it is important for sniff authors to have access to this information (to allow them to fix the sniff), this is not user-friendly for end-users who cannot do anything with that information, other than report it to the relevant standard and in the mean time, their code is not fully scanned.

So... I'm wondering if we cannot find a way to make this more user-friendly for end-users, while still keeping the information available for sniff authors.

Important caveat: while the scan results for the "rest of the file" will be fine for PHP deprecations/notices/warnings caused by a logic oversight in the sniff or a change in PHP, if the file being scanned contains a parse error, chances are high that the scan results for the "rest of the file" are unreliable (at best) or even complete nonsense (at worst).

Proposal

I haven't thought this through completely yet, but these are some thoughts I have around this which I'm sharing to receive feedback on them.

Rough outline of proposal:

  • Leave the existing behaviour in place for fatal errors.
  • Collect all deprecations/notices/warnings seen during the scan, but don't abort scanning a file on those.
  • Report the number of deprecations/notices/warnings encountered during a scan at the bottom of the output and exit with 1 if any were seen (same as before as previously the Internal.Exception would cause an exit code of 1).
  • Report the full details of deprecations/notices/warnings encountered during a scan at the bottom of the output when running with -v and exit with 1 if any were seen (same as before).
  • Add a new CLI argument --ignore-php-notices (or something along those lines) to allow the exit code to be 0 if there were deprecations/notices/warnings.
  • In PHPCS 4.0.0, reverse the behaviour for the exit code, meaning PHP deprecations/notices/warnings will no longer cause an exit code of 1, but will exit with 0 instead. Replace the --ignore-php-notices CLI argument with a --fail-on-php-notices CLI argument to still get a 1 exit code when there are notices.

We also may need to make some accommodation in the test framework to allow test runs to still always report those deprecations/notices/warnings and fail a test run if any are encountered.

Thoughts ?


Issue squizlabs/PHP_CodeSniffer#2871 is related.

Support new PHP 8.3 syntaxes

PHP 8.3 includes the following new syntaxes for which it should be verified if the Tokenizer needs updates and/or whether any sniffs need updates:

To Do

  • Dynamic class constant fetch - C::{$name}
    • Tokenizer changes needed ?
    • Sniff updates needed ?
  • Tokenization change for yield from - see #529
    • Tokenizer changes needed
    • Sniff updates needed

Done

Generic.WhiteSpace.ScopeIndent false positive with nested `match`-es

Describe the bug

The ScopeIndent sniff suggests a quite strange indentation when processing multi-nested match-statements

// It's a copy of my bug report from the old repo (squizlabs/PHP_CodeSniffer#3875)
// Thank you, Juliette, for an amazing initiative in keeping the project going!

Code sample

<?php

echo match (1) {
    0 => match (2) {
        2 => match (3) {
            3 => 3,
            default => -1,
        },
    },
    1 => match (2) {
        1 => match (3) {
            3 => 3,
            default => -1,
        },
        2 => match (3) {
            3 => 3,
            default => -1,
        },
    },
};

How that code will look if formatted as suggested

<?php

echo match (1) {
    0 => match (2) {
        2 => match (3) {
            3 => 3,
            default => -1,
        },
    },
    1 => match (2) {
        1 => match (3) {
            3 => 3,
            default => -1,
        },
            2 => match (3) {
                3 => 3,
                default => -1,
            },
    },
};

Custom ruleset

N/A — reproducible with PSR12

To reproduce

Steps to reproduce the behavior:

  1. Create a file called test.php with the code sample above
  2. Run phpcs -s --standard=psr12 test.php
  3. See errors displayed
------------------------------------------------------------------------------------------------------------------------------
FOUND 4 ERRORS AFFECTING 4 LINES
------------------------------------------------------------------------------------------------------------------------------
 15 | ERROR | [x] Line indented incorrectly; expected at least 12 spaces, found 8
    |       |     (Generic.WhiteSpace.ScopeIndent.Incorrect)
 16 | ERROR | [x] Line indented incorrectly; expected at least 16 spaces, found 12
    |       |     (Generic.WhiteSpace.ScopeIndent.Incorrect)
 17 | ERROR | [x] Line indented incorrectly; expected at least 16 spaces, found 12
    |       |     (Generic.WhiteSpace.ScopeIndent.Incorrect)
 18 | ERROR | [x] Line indented incorrectly; expected 12 spaces, found 8 (Generic.WhiteSpace.ScopeIndent.IncorrectExact)
------------------------------------------------------------------------------------------------------------------------------
PHPCBF CAN FIX THE 4 MARKED SNIFF VIOLATIONS AUTOMATICALLY
------------------------------------------------------------------------------------------------------------------------------

Expected behavior

No indentation errors.

Versions (please complete the following information)

Operating System macOS 12.5
PHP version 8.0
PHP_CodeSniffer version 3.9.0
Standard PSR2
Install type Local composer

Additional context

none

Please confirm:

  • I have searched the issue list and am not opening a duplicate issue.
  • I confirm that this bug is a bug in PHP_CodeSniffer and not in one of the external standards.
  • I have verified the issue still exists in the master branch of PHP_CodeSniffer.

Generic/MultipleStatementAlignment: false positive with non-scoped control structures

Repost from squizlabs/PHP_CodeSniffer#2578:

Ported over from: squizlabs/PHP_CodeSniffer#2529 (comment)

$phrase = 'phrase';
if ($a === true)
    if ($b === true)
        $phrase = 'another phrase';
else
    $phrase = 'different phrase';

Throws:

 3 | WARNING | [x] Equals sign not aligned with surrounding assignments; expected 9
   |         |     spaces but found 1 space
   |         |     (Generic.Formatting.MultipleStatementAlignment.NotSameWarning)
 8 | WARNING | [x] Equals sign not aligned with surrounding assignments; expected 5
   |         |     spaces but found 1 space
   |         |     (Generic.Formatting.MultipleStatementAlignment.NotSameWarning)

Caused by the control structure not having any braces.

Fatal error when using Gitblame report from subdirectory when ruleset has basepath

Repost from squizlabs/PHP_CodeSniffer#3854:

Describe the bug

When basepath is set in a custom ruleset AND PHPCS is subsequently run from within a subdirectory of the project AND the Gitblame report is requested, a fatal error happens.

As far as I can see, this is due to the $filename which is being passed to Gitblame::getBlameContent() not being the full path to the file, but the path with the basename stripped off.

To reproduce

Steps to reproduce the behavior with PHPCS itself:

  1. Change into the src directory of the PHPCS project
  2. Run phpcs -psl . --report=gitblame
  3. See the following error message displayed
PHP_CodeSniffer version 3.7.2 (stable) by Squiz (http://www.squiz.net)

Fatal error: Uncaught PHP_CodeSniffer\Exceptions\RuntimeException: chdir(): No such file or directory (errno 2) in path/to/src/Reports/Gitblame.php on line 72 in path/to/src/Runner.php:608
Stack trace:
#0 [internal function]: PHP_CodeSniffer\Runner->handleErrors(2, 'chdir(): No suc...', '...', 72)
#1 path/to/src/Reports/Gitblame.php(72): chdir('src')
#2 path/to/src/Reports/VersionControl.php(43): PHP_CodeSniffer\Reports\Gitblame->getBlameContent('src\\Config.php')
#3 path/to/src/Reporter.php(285): PHP_CodeSniffer\Reports\VersionControl->generateFileReport(Array, Object(PHP_CodeSniffer\Files\LocalFile), true, 150)
#4 path/to/src/Runner.php(700): PHP_CodeSniffer\Reporter->cacheFileReport(Object(PHP_CodeSniffer\Files\LocalFile), Object(PHP_CodeSniffer\Config))
#5 path/to/src/Runner.php(438): PHP_CodeSniffer\Runner->processFile(Object(PHP_CodeSniffer\Files\LocalFile))
#6 path/to/src/Runner.php(116): PHP_CodeSniffer\Runner->run()
#7 path/to/bin/phpcs(18): PHP_CodeSniffer\Runner->runPHPCS()
#8 {main}
  thrown in path/to/src/Runner.php on line 608

Exit code is 255

Expected behavior

No fatal error and the git blame report is displayed correctly

Versions (please complete the following information)

Operating System Windows 10
PHP version 8.2.7 (but not relevant)
PHP_CodeSniffer version bleeding edge including the fix from squizlabs/PHP_CodeSniffer#3809
Standard PHPCS native phpcs.xml.dist
Install type git clone

Additional context

This issue is loosely related to squizlabs/PHP_CodeSniffer#3809.


PR upcoming.

Feature: baseline violations

In a large existing codebase, it usually not possible to fix all violations at once. Or when new violations appear when new rules are added. Think for example the Slevomat Coding Standard. This feature will allow to create a baseline of the current violations, and only report new violations. This is a proposal to add a baseline feature:

Commandline

Create a baseline, and save it to the --baseline-file <path> or default to phpcs-baseline.xml

vendor/bin/phpcs ... --generate-baseline [--baseline-file=<path>]

Update the baseline, but only remove, not add new violations

vendor/bin/phpcs ... --update-baseline [--baseline-file=<path>]

Using the baseline. If --baseline-file argument is absent will look for phpcs-baseline.xml in the root of the project.

vendor/bin/phpcs ... [--baseline-file=<path>]

To ignore the current baseline:

vendor/bin/phpcs ... --ignore-baseline

Options for baseline file format

Which baseline format would we prefer?

  • xml: No additional dependency, due to the ext-simplexml dependency.
  • json: can be read with if the ext-json dependency is added.
  • neon: requires additional dependency, for example nette/neon.

Proposal for baseline file name

  • phpcs-baseline._format. Similar to PHPStan's phpstan-baseline.neon.
  • default location is the root of the project. Root is where /vendor/ directory lives.

Proposal for strict mode

  • Add a strict option in which violations that are in the baseline but do not appear will
    result in a violation. Commandline option: --baseline-strict ( ? )

Violation tracking strategies

To be able to track violations, we need to be able to identify them. We minimally need:

  • file path: This is the file path the violation occurred in. The file path will be normalized to be relative to the project root and only contain forward slashes.
  • Ignore the line in the file a violation occurs. Modifications to the top of the file will have unwanted effects.

Further the following strategies can be chosen:

Code signature:

  • the name of the sniff: For example PSR12.Files.FileHeader.SpacingAfterBlock.
  • hash of surrounding code: The code surrounding the violation is hashed. This is a very strict strategy, but
    also very sensitive to changes in the code. Downside there's a performance penalty for hashing the code.

Example:

<?xml version="1.0" encoding="UTF-8"?>
<phpcs-baseline>
    <violation file="relative/path/to/file" 
               sniff="PSR12.Files.FileHeader.SpacingAfterBlock" 
               signature="81a547481bf2e1839bf4cff69dffeb6674dbc203"
    />
</phpcs-baseline>

Violation count:

  • the name of the sniff: For example PSR12.Files.FileHeader.SpacingAfterBlock.
  • count the number of violations: Keep track of that PSR12.Files.FileHeader.SpacingAfterBlock occurs at most 2 times
    in the file. This is a very loose strategy, but also very insensitive to changes in the code. Downside is that
    it's not very strict, and it's not possible to track the specific violation messages. It will however prevent
    additional violations from being added.

Example:

<?xml version="1.0" encoding="UTF-8"?>
<phpcs-baseline>
    <violation file="relative/path/to/file" 
               sniff="PSR12.Files.FileHeader.SpacingAfterBlock" 
               count="2"
    />
</phpcs-baseline>

Violation message:

  • the name of the sniff: For example PSR12.Files.FileHeader.SpacingAfterBlock.
  • the violation message: Keep track of the specific violation message. Token index and
    line number should be excluded here as adding code above the violation with change these values.
    The difference with the strategy above is that different messages within the same Sniff can be
    baselined. This will improve accuracy.
  • count the number of violations: In this strategy also keep count of the violations.

Example:

<?xml version="1.0" encoding="UTF-8"?>
<phpcs-baseline>
    <violation file="relative/path/to/file" 
               sniff="PSR2.Classes.ClassDeclaration.CloseBraceAfterBody"
               message="The closing brace for the class must go on the next line after the body"
               count="1"
    />
</phpcs-baseline>

Final words

In short:

  • Choose file format: xml, json, or neon

  • Choose track strategy: code signature, violation count or message + violation count

  • I intend to create a pull request to implement this feature. See #115

Tokenizer/scope mapping: scope owner not correctly set with heredoc in condition

Describe the bug

The 'scope_condition' key doesn't always get set correctly in the $tokens array.
Consequently, tokens within the curlies do not get the 'conditions' array set correctly either.

Both things can trip sniffs up.

Code sample

// Correct: the curlies get assigned the "if" as "scope condition".
if (true) {
    return;
}

// Bug: the curlies do NOT get a "scope condition" assigned, while it should be the "if".
if (foo(<<<EOD
foobar!
EOD
)) {
    return;
}

Token debug output

Ptr | Ln  | Col  | Cond | ( #) | Token Type                 | [len]: Content
--------------------------------------------------------------------------
  0 | L01 | C  1 | CC 0 | ( 0) | T_OPEN_TAG                 | [  5]: <?php

  1 | L02 | C  1 | CC 0 | ( 0) | T_WHITESPACE               | [  0]:

  2 | L03 | C  1 | CC 0 | ( 0) | T_IF                       | [  2]: if
  3 | L03 | C  3 | CC 0 | ( 0) | T_WHITESPACE               | [  1]: ⸱
  4 | L03 | C  4 | CC 0 | ( 0) | T_OPEN_PARENTHESIS         | [  1]: (
  5 | L03 | C  5 | CC 0 | ( 1) | T_TRUE                     | [  4]: true
  6 | L03 | C  9 | CC 0 | ( 0) | T_CLOSE_PARENTHESIS        | [  1]: )
  7 | L03 | C 10 | CC 0 | ( 0) | T_WHITESPACE               | [  1]: ⸱
  8 | L03 | C 11 | CC 0 | ( 0) | T_OPEN_CURLY_BRACKET       | [  1]: {
  9 | L03 | C 12 | CC 1 | ( 0) | T_WHITESPACE               | [  0]:

 10 | L04 | C  1 | CC 1 | ( 0) | T_WHITESPACE               | [  4]: ⸱⸱⸱⸱
 11 | L04 | C  5 | CC 1 | ( 0) | T_RETURN                   | [  6]: return
 12 | L04 | C 11 | CC 1 | ( 0) | T_SEMICOLON                | [  1]: ;
 13 | L04 | C 12 | CC 1 | ( 0) | T_WHITESPACE               | [  0]:

 14 | L05 | C  1 | CC 0 | ( 0) | T_CLOSE_CURLY_BRACKET      | [  1]: }
 15 | L05 | C  2 | CC 0 | ( 0) | T_WHITESPACE               | [  0]:

 16 | L06 | C  1 | CC 0 | ( 0) | T_WHITESPACE               | [  0]:

 17 | L07 | C  1 | CC 0 | ( 0) | T_IF                       | [  2]: if
 18 | L07 | C  3 | CC 0 | ( 0) | T_WHITESPACE               | [  1]: ⸱
 19 | L07 | C  4 | CC 0 | ( 0) | T_OPEN_PARENTHESIS         | [  1]: (
 20 | L07 | C  5 | CC 0 | ( 1) | T_STRING                   | [  3]: foo
 21 | L07 | C  8 | CC 0 | ( 1) | T_OPEN_PARENTHESIS         | [  1]: (
 22 | L07 | C  9 | CC 0 | ( 2) | T_START_HEREDOC            | [  6]: <<<EOD

 23 | L08 | C  1 | CC 1 | ( 2) | T_HEREDOC                  | [  7]: foobar!

 24 | L09 | C  1 | CC 0 | ( 2) | T_END_HEREDOC              | [  3]: EOD
 25 | L09 | C  4 | CC 0 | ( 2) | T_WHITESPACE               | [  0]:

 26 | L10 | C  1 | CC 0 | ( 1) | T_CLOSE_PARENTHESIS        | [  1]: )
 27 | L10 | C  2 | CC 0 | ( 0) | T_CLOSE_PARENTHESIS        | [  1]: )
 28 | L10 | C  3 | CC 0 | ( 0) | T_WHITESPACE               | [  1]: ⸱
 29 | L10 | C  4 | CC 0 | ( 0) | T_OPEN_CURLY_BRACKET       | [  1]: {
 30 | L10 | C  5 | CC 0 | ( 0) | T_WHITESPACE               | [  0]:

 31 | L11 | C  1 | CC 0 | ( 0) | T_WHITESPACE               | [  4]: ⸱⸱⸱⸱
 32 | L11 | C  5 | CC 0 | ( 0) | T_RETURN                   | [  6]: return
 33 | L11 | C 11 | CC 0 | ( 0) | T_SEMICOLON                | [  1]: ;
 34 | L11 | C 12 | CC 0 | ( 0) | T_WHITESPACE               | [  0]:

 35 | L12 | C  1 | CC 0 | ( 0) | T_CLOSE_CURLY_BRACKET      | [  1]: }
 36 | L12 | C  2 | CC 0 | ( 0) | T_WHITESPACE               | [  0]:

As can be seen here, token 9 - 13 correctly have the scope conditions set, while token 30 - 34 do not.

Expected behavior

That the conditions get set correctly in all cases ;-)

Versions (please complete the following information)

Operating System not relevant
PHP version 8.2.13, though shouldn't be relevant
PHP_CodeSniffer version master
Standard not relevant
Install type git clone

Please confirm:

  • I have searched the issue list and am not opening a duplicate issue.
  • I confirm that this bug is a bug in PHP_CodeSniffer and not in one of the external standards.
  • I have verified the issue still exists in the master branch of PHP_CodeSniffer.

Support new PHP 8.2 syntaxes

PHP 8.2 includes the following new syntaxes for which it should be verified if the Tokenizer needs updates and/or whether any sniffs need updates:

To do

All done

Done

Analysis: determine whether to revive of not

The original PHP_CodeSniffer project contained a code consistency analysis website: https://squizlabs.github.io/PHP_CodeSniffer/analysis/

That website hadn't been updated since 2018.

For now, I've removed the site from the gh-pages branch of this repo.

I'm not sure if there is still interest in the analysis website. If so, reviving it under a new (sub)domain would be an option, though the code to generate the site would probably need revision and a critical look as to which projects should be analyzed.

This ticket is intended to measure interest.

Leave a 👍🏻 if you are interested in having this analysis website revived.
Leave a comment if you want to get involved in reviving the analysis website.

Refs:

Errors for lines containing error suppression comments are always suppressed

Repost from squizlabs/PHP_CodeSniffer#1826:

The new error suppression system ignores all notices for lines which only contain the new PHPCS native whitelist comments // phpcs:.....

While this is great for, for instance, the LineLength sniff, it also means that, for instance, the SuperfluousWhitespace or DisallowTabIndent sniffs will not work for the lines containing these type of comments. Which means you still could end up with tab indentation even when space indentation is enforced.

Also, the suppression on all notices for lines which only contain the new PHPCS native whitelist comment, also prevents examining these comments.

I was already discussing for one project to not allow "blanket" comment, i.e. // phpcs:disable without a sniffcode would not be allowed to be used in that project.
Similarly, for that project, we would want to enforce, that all whitelist comments (except // phpcs:enable) have to be accompanied by a reason for whitelisting.

Suppressing all errors for these type of lines, would also prevent any automated checks for this.

Any thoughts ?


See the original issue for an extensive discussion on possible approaches.

4.0 | Make sure that everything which was deprecated in 3.x has been removed in 4.0

  • 3.2.0: Old-style ignore annotation syntax
  • 3.3.0: Old-style (comma-delimited string) setting of array properties
  • 3.3.0: T_ARRAY_HINT Token
  • 3.3.0: T_RETURN_TYPE Token
  • 3.3.0: Squiz.WhiteSpace.LanguageConstructSpacing Sniff
  • 3.4.0: Generic.Formatting.NoSpaceAfterCast Sniff
  • 3.5.7: The new method of PHP 8.0 tokenizing for namespaced names has been reverted to the pre 8.0 method. This change will be removed in PHPCS 4.0 as the PHP 8.0 tokenizing method will be backported for pre 8.0 versions
  • 3.8.0: The third parameter for the Ruleset::setSniffProperty() method has been changed to expect an array, Existing code will continue to work but will throw a deprecation error
  • [3.9.0]: The complete MySource standard - #276 + squizlabs/PHP_CodeSniffer#2471
  • [3.9.0]: JS/CSS support + all JS/CSS specific sniffs - #276 + squizlabs/PHP_CodeSniffer#2448
  • [3.9.0]: ExactMatch::getBlacklist() and ExactMatch::getWhitelist() methods - see #198 and #199
  • [3.9.0]: Zend.Debug.CodeAnalyzer - see #277 / #58

Handling of list() language construct

Repost from squizlabs/PHP_CodeSniffer#1699:

Proposal: add list() to the Tokens::$functionNameTokens property

While list is a language construct, for the purpose of formatting, it is normally treated as if it were a function call, similar to how isset() or empty() are treated.

To that end, I propose adding list to the Tokens::$functionNameTokens property.

There are two sniffs within PHPCS whose behaviour will change if this proposal is accepted:

  • Generic.Functions.FunctionCallArgumentSpacing
  • PEAR.Functions.FunctionCallSignature (and by extension PSR2.Methods.FunctionCallSignature)

For the Generic.Functions.FunctionCallArgumentSpacing, it would mean that a slight adjustment is needed to account for the possibility of an empty element, like in list($drink, , $power) = $info; which would otherwise trigger a no space allowed before comma error.

I'd be happy to create a PR to handle this if there is support for this proposal.

Opinions ?

QA: "normalize" the code style rules used by this code base a little

The coding standard of this code base was historically/organically grown and is likely influenced by some internal rules which were being used in Squiz projects at one time or another.

Changing the code style to PSR12 with some extra rules (i.e. PHPCSDevCS) would cause lots and lots of code churn, so is not on the table at this time.

However, I do think there are some rules which can (and should) be changed in the near future.
On the one hand, these rules cause code churn on lines unrelated to the actual code change being made.
On the other hand, these rules catch contributors out a lot as they are contrary to what most code bases nowadays expect, making contributing to this code base more painful for new contributors than necessary.

My personal top 5 of "annoying" rules which are being enforced is:

  1. End comments at the end of "long" control structures/functions/classes.
  2. else if instead of elseif
  3. No spaces around a concatenation operator.
  4. The case/default statements in switch statements not being indented by four spaces - changing this would cause lots of code churn in the test files though.
  5. Unnecessary blank lines at the end of each function/class.

I'm opening this issue to allow for people to voice their opinion on this.

  • Do the above five rules bother you or not ?
  • Are there other rules, not mentioned above, which catch you out often when contributing ?
  • Do you think the code churn caused by changing these rules and updating the code base to comply is worth it ?

I'm going to leave this ticket open for a few weeks and will decide on a course of action and timeline after that.

/cc @fredden

Tests: expand the unit test suite

As of PR #144, code coverage will now be measured and recorded for every PR and push.

The resulting reports can be found here: https://coveralls.io/github/PHPCSStandards/PHP_CodeSniffer

As can be seen there, code coverage for the sniffs is pretty good, but for most other areas of the code... not so much.

The test suite should be expanded to allow for merging with (more) confidence.

Some thoughts on this:

  • While there are tests covering parts of the PHP_CodeSniffer\Tokenizers\PHP class, these tests don't currently register code coverage due to the test set up.
    This may be fixable with some tweaks to the existing AbstractMethodUnitTest test case, but may also require a separate test case class to get this working.
    I will probably look into this myself.
    Fixed via #314
  • For both the Generators as well as the Reports, a new abstract test case may need to be introduced to get those tests set up more easily.

Getting started

  • Adding additional tests for individual sniffs will likely be most straight forward for new contributors. The CONTRIBUTING guide contains information about writing sniff related tests.
    • When creating additional tests for sniffs, don't get too focused on covering uncovered lines.
      Think about what the sniff is checking for and get creative with writing horribly formatted code to make sure the sniff detects this correctly.
    • Also keep in mind that some sniffs are pretty "old" and may or may not take all new PHP syntaxes into account correctly.
      Adding tests with modern PHP syntaxes is a huge help, cause even if the sniff already handles this syntax correctly, the tests will safeguard that it continues to do so, even when the code in the sniff changes.
    • When adding tests for sniff code which is related to parse errors, keep the guidelines outlined in #143 in mind.
  • Another area which should be reasonably straight forward to add tests for are some of the methods in the src/Util directory, like those in the Timing and Common classes.

Writing new tests for non-sniff code will be more complicated and may require some creativeness in setting those up. When in doubt on whether your approach is the right one, please discuss before execute.

When writing tests, keep in mind that the tests need to be able to run on PHP 5.4 (PHPUnit 4.x) up to PHP 8.3/4 (PHPUnit 9.x).

PRs related to this task should preferably only touch the tests for one sniff/one class/one function per PR.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.