phpcsstandards / php_codesniffer Goto Github PK
View Code? Open in Web Editor NEWPHP_CodeSniffer tokenizes PHP files and detects violations of a defined set of coding standards.
License: BSD 3-Clause "New" or "Revised" License
PHP_CodeSniffer tokenizes PHP files and detects violations of a defined set of coding standards.
License: BSD 3-Clause "New" or "Revised" License
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.
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 byT_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 toT_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.
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:
- the order in which the files are sniffed which may change without notice;
- 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 areinclude
d from within a function in another file. For those files it would be useful to be able to set a propertyFileType 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 aglobal
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.
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 asphpcbf
?- 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.
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.
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.
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
------------------------------------------------------------------------------------------------------------------
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
------------------------------------------------------------------------------------------------------------------
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
-----------------------------------------------------------------------------------------------------------
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
------------------------------------------------------------------------------------------------------------------
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
-----------------------------------------------------------------------------------------------------------
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.
For each of the files listed above leading to a fixer conflict, it needs to be determined whether:
*.conflictcheck
to your .git/info/exclude
(will be added to .gitignore
when the fixer conflict check will be added for real).-vvv
flag.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.
Repost from squizlabs/PHP_CodeSniffer#2962:
The
Generic.ControlStructures.DisallowYodaConditions
reports aUsage 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;
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
The CONTRIBUTING doc contains information on writing sniff documentation and guidelines which should be followed.
PSR12.Files.DeclareStatement
(There is a first draft available created by @dingo-d, which can be iterated on #187)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.
Generic.Arrays.ArrayIndent
- @rodrigoprimo #432Generic.Commenting.DocComment
- @rodrigoprimo #247Generic.VersionControl.GitMergeConflict
- @rodrigoprimoSquiz.WhiteSpace.ControlStructureSpacing
- @jonmcpSquiz.WhiteSpace.FunctionOpeningBraceSpace
- @jonmcpSquiz.WhiteSpace.FunctionSpacing
- @jonmcp #451Squiz.WhiteSpace.LogicalOperatorSpacing
- @jonmcpSquiz.WhiteSpace.OperatorSpacing
- @jonmcpGeneric.CodeAnalysis.EmptyPHPStatement
- @rodrigoprimo #166Generic.Formatting.SpaceBeforeCast
- @rodrigoprimo #159Generic.PHP.RequireStrictTypes
- @rodrigoprimo #236Generic.PHP.Syntax
- @rodrigoprimo #175Generic.WhiteSpace.IncrementDecrementSpacing
- @rodrigoprimo #287Generic.WhiteSpace.LanguageConstructSpacing
- @rodrigoprimo #177PSR12.Classes.ClosingBrace
- @dingo-d #170PSR12.Classes.OpeningBraceSpace
- @dingo-d #171PSR12.ControlStructures.BooleanOperatorPlacement
- @dingo-d #181PSR12.ControlStructures.ControlStructureSpacing
- @dingo-d #182PSR12.Files.ImportStatement
- @dingo-d #232PSR12.Files.OpenTag
- @dingo-d #233PSR12.Functions.ReturnTypeDeclaration
- @dingo-d #237PSR12.Properties.ConstantVisibility
- @dingo-d #238Squiz.WhiteSpace.FunctionClosingBraceSpace
- @przemekhernik #408Squiz.WhiteSpace.MemberVarSpacing
- @jonmcp #373Squiz.WhiteSpace.ScopeClosingBrace
- @jonmcp #353Squiz.WhiteSpace.SuperfluousWhitespace
- @jonmcp #352Leave 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.
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:
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
- Should the
T_OPEN_TAG_WITH_ECHO
token be added to the sniff ?- 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 ?
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.
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.
Duplicated from squizlabs/PHP_CodeSniffer#3889 (and updated from later comments)
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.
<?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;
N/A
Steps to reproduce the behavior:
test1.php
and test2.php
with the code samples above.phpcs -s --standard=PSR12 test1.php test2.php
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
--------------------------------------------------------------------------------------------------------------------------------
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.
Operating System | Debian sid |
PHP version | 8.2.12 |
PHP_CodeSniffer version | 3.7.2, master |
Standard | PSR12 |
Install type | Composer local |
It seems that in this situation it's setting $ignoring['.except'][...]
, which overrides phpcs:ignore
.
master
branch of PHP_CodeSniffer.There are many packages that depend on squizlabs/php_codesniffer
and I can't install this package because the release version does not include Composer's replace
directive added in #1.
Please make a minor release such as 3.7.3 including changes from #1. Thanks!
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, likeGeneric
) 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 upphpcs -i
.I'd like to propose making that a feature available to external standards as well.
For one, I imagine theSlevomatCodingStandard
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 thexsd
and adjusting the code for the-i
option to respect the setting found there.Something like
list
with the default beingtrue
.<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 theStandards::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.
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:
4.0
branch will need to reset that branch after the rebase.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.
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.
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).
The tests for the Generic.ControlStructures.InlineControlStructure
sniff: https://github.com/PHPCSStandards/PHP_CodeSniffer/tree/master/src/Standards/Generic/Tests/ControlStructures
InlineControlStructureUnitTest.1.inc
does not contain a parse error test at the end.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.
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.
Typical ways to approach this task:
Some practical guidelines:
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.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.
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):
- Rename abstract base test cases. Those classes are no longer allowed to have the
Test
suffix.
I'd recommend renaming the suffix fromUnitTest
toTestCase
.
See: sebastianbergmann/phpunit#5132- Changing the test suite set up to remove the use of the old style set up with
AllTests.php
andAllSniffs.php
containing a staticsuite
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 theAllTests
andAllSniffs
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 testbootstrap.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.
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.
<?php
$x=1;
N/A
Steps to reproduce the behavior:
test.php
with the code sample above.phpcs -s --report-width=100000 --standard=PSR12 test.php
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
---------------------------------------------------------------------------------------------------------------
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
---------------------------------------------------------------------------------------------------------------
Operating System | Debian sid |
PHP version | 8.2.12 |
PHP_CodeSniffer version | 3.7.2, master |
Standard | PSR12 |
Install type | Composer local |
The problem seems to be that the four non-displaying characters (\033[0m
) added at
PHP_CodeSniffer/src/Reports/Full.php
Line 139 in c248a92
$maxErrorLength
at PHP_CodeSniffer/src/Reports/Full.php
Line 69 in c248a92
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.
master
branch of PHP_CodeSnifferThe 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:
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).
Duplicated from here, as requested.
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
'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
Steps to reproduce the behavior:
test.php
with the code sample aboveOperating System | Windows 10] |
PHP version | 7.4.3 |
PHP_CodeSniffer version | [e.g., 3.5.5, master] |
Standard | Squiz] |
Add any other context about the problem here.
master
branch of PHP_CodeSniffer.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 theforbiddenFunctions
property in a standard and thenextend
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
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
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
phpcs --standard=.phpcs.xml.dist,subdir/.phpcs.dir.xml
, loading the subdirectory ruleset as a peer of the parent's, orsubdir/.phpcs.dir.xml
as the ruleset, but treat that file as if it had <rule ref="../.phpcs.xml.dist" />
at the start.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:
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.PHP_CodeSniffer\Config
class is half-static, <config>
doesn't work well at a per-directory level.
<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.--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.
Repost from squizlabs/PHP_CodeSniffer#3118:
I was just wondering why
isset()
,unset()
andempty()
- 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()
andeval()
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.
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:
~/.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 😉
N/A
N/A
Steps to reproduce the behavior:
composer global require phpcsstandards/php_codesniffer
phpcs --version
.~/.composer/vendor # phpcs --version
PHP_CodeSniffer version 3.7.2 (stable) by Squiz (http://www.squiz.net)
The output should write a message referring to this project.
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) |
N/A
master
branch of PHP_CodeSniffer.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: 90I 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/WPThemeReviewFor standards which do not (yet) supply the version number via the
ruleset.xml
file, it could be tried to retrieve the version number via acomposer --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.
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-destructuringNow 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:
- 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.- 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#635If 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.
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 tofindPrevious()
are the same, the function will work as expected. However, the same can not be said about thefindNext()
method as in that case it will always returnfalse
.This is caused by the
findPrevious()
method treating the end position as inclusivefor ($i = $start; $i >= $end; $i--)
, while thefindNext()
method treats it as exclusivefor ($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.
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.
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/
/PHIVE etc.composer.json
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:
- https://github.com/sponsors/phpcsstandards
- https://opencollective.com/php_codesniffer
- https://github.com/sponsors/jrfnl
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.
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 whetherlibxml
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.
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:
PER-200
, to prevent it from becoming a moving target failing builds at random.PER-latest
, which would include the ruleset for the current version and would need to be updated each time a new version is added.PSR-PER
.PSR-PER
repo would only contain rulesets, not sniffs.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.
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;
Follow up on #46
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 checked3.6.2
tag- Standard: custom
Additional context
I haven't done agit 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.
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.
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 theinstanceof
operator.This defies the principle of least astonishment as both
self
andparent
in combination withinstanceof
are tokenized asT_SELF
andT_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 asT_STATIC
when preceded byinstanceof
.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 theSquiz.WhiteSpace.ScopeKeywordSpacing
sniff, not in the Tokenizer, same as is done in the sniff with other typical late static binding occurrences.Code sample
if ($geometry instanceof static) { echo 'foo'; }
static
in the above code sample is tokenized asT_STRING
, notT_STATIC
.
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:
-v
: file specific token and line counts with running times- -
vv
: the info from level 1 + verbose tokeniser output-vvv
: the info from level 1 + 2 + token processing output with sniff running timesNow 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.
- Add an extra debugging level between the current
1
(-v
) and2
(-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.- 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.- Create a
Performance
Report
type, possibly externally hosted, like in PHPCSDevTools.
To allow for this, some changes would be needed to theFile::process()
method as it currently only records "time taken by each sniff" to the$this->listenerTimes
property ifPHP_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 theFile::getMetrics()
method, there would also be aFile::getListenerTimes()
method.
It would still need some work-arounds as$this->listenerTimes
is cumulative and only theReport::generateFileReport()
method has access to theFile
object, while the report would need to be generated in thegenerate()
method which doesn't have access to theFile
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.
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 theInternal.Exception
would cause an exit code of1
).- Report the full details of deprecations/notices/warnings encountered during a scan at the bottom of the output when running with
-v
and exit with1
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 be0
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 with0
instead. Replace the--ignore-php-notices
CLI argument with a--fail-on-php-notices
CLI argument to still get a1
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.
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:
C::{$name}
yield from
- see #529
new readonly class {};
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!
<?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,
},
},
};
<?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,
},
},
};
N/A — reproducible with PSR12
Steps to reproduce the behavior:
test.php
with the code sample abovephpcs -s --standard=psr12 test.php
------------------------------------------------------------------------------------------------------------------------------
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
------------------------------------------------------------------------------------------------------------------------------
No indentation errors.
Operating System | macOS 12.5 |
PHP version | 8.0 |
PHP_CodeSniffer version | 3.9.0 |
Standard | PSR2 |
Install type | Local composer |
none
master
branch of PHP_CodeSniffer.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.
... and add a develop
branch as the default WIP branch. The stable
branch will become the release-only branch.
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 theGitblame
report is requested, a fatal error happens.As far as I can see, this is due to the
$filename
which is being passed toGitblame::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:
- Change into the
src
directory of the PHPCS project- Run
phpcs -psl . --report=gitblame
- 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 correctlyVersions (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.
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:
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
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
.phpcs-baseline._format
. Similar to PHPStan's phpstan-baseline.neon./vendor/
directory lives.--baseline-strict
( ? )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.Further the following strategies can be chosen:
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, butExample:
<?xml version="1.0" encoding="UTF-8"?>
<phpcs-baseline>
<violation file="relative/path/to/file"
sniff="PSR12.Files.FileHeader.SpacingAfterBlock"
signature="81a547481bf2e1839bf4cff69dffeb6674dbc203"
/>
</phpcs-baseline>
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 timesExample:
<?xml version="1.0" encoding="UTF-8"?>
<phpcs-baseline>
<violation file="relative/path/to/file"
sniff="PSR12.Files.FileHeader.SpacingAfterBlock"
count="2"
/>
</phpcs-baseline>
the name of the sniff
: For example PSR12.Files.FileHeader.SpacingAfterBlock
.the violation message
: Keep track of the specific violation message. Token index andcount 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>
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
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.
// 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;
}
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.
That the conditions get set correctly in all cases ;-)
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 |
master
branch of PHP_CodeSniffer.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:
All done
getClassProperties()
- PR squizlabs/PHP_CodeSniffer#3686null
, false
, true
as stand-alone types
getMethodProperties()
, getMethodParameters()
, getMemberProperties()
- PR squizlabs/PHP_CodeSniffer#3662 / #49The 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:
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, theSuperfluousWhitespace
orDisallowTabIndent
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.
Repost from squizlabs/PHP_CodeSniffer#1699:
Proposal: add
list()
to theTokens::$functionNameTokens
propertyWhile
list
is a language construct, for the purpose of formatting, it is normally treated as if it were a function call, similar to howisset()
orempty()
are treated.To that end, I propose adding
list
to theTokens::$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 extensionPSR2.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 inlist($drink, , $power) = $info;
which would otherwise trigger ano space allowed before comma
error.I'd be happy to create a PR to handle this if there is support for this proposal.
Opinions ?
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:
else if
instead of elseif
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.I'm opening this issue to allow for people to voice their opinion on this.
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
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.
PHP_CodeSniffer\Tokenizers\PHP
class, these tests don't currently register code coverage due to the test set up.AbstractMethodUnitTest
test case, but may also require a separate test case class to get this working.Generators
as well as the Reports
, a new abstract test case may need to be introduced to get those tests set up more easily.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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.