A Set of Static Analyzers for PHP Code
A static analyzer scans the source code for errors and vulnerabilities and for compliance with the coding standard.
The article describes how to install, configure and run static analyzers:
PHPStan
Installation
composer require --dev phpstan/phpstan
Run
vendor/bin/phpstan analyze -l 9 src
Psalm
Installation
composer require --dev vimeo/psalm
Configuration
src/psalm.xml<?xml version="1.0"?>
<psalm
errorLevel="7"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
findUnusedBaselineEntry="true"
>
<projectFiles>
<directory name="src" />
<ignoreFiles>
<directory name="vendor" />
</ignoreFiles>
</projectFiles>
<issueHandlers>
<PropertyNotSetInConstructor>
<errorLevel type="suppress">
<directory name="src" />
</errorLevel>
</PropertyNotSetInConstructor>
</issueHandlers>
</psalm>
Run
vendor/bin/psalm -c psalm.xml --show-info=true
PHP_CodeSniffer
Installation
composer require --dev squizlabs/php_codesniffer
composer require --dev slevomat/coding-standard
Configuration
src/phpcs_ruleset.xml<?xml version="1.0"?>
<ruleset name="App">
<rule ref="vendor/slevomat/coding-standard/SlevomatCodingStandard/ruleset.xml">
<exclude name="SlevomatCodingStandard.TypeHints.DeclareStrictTypes.IncorrectStrictTypesFormat"/>
<exclude name="SlevomatCodingStandard.Namespaces.UseOnlyWhitelistedNamespaces.NonFullyQualified"/>
<exclude name="SlevomatCodingStandard.Attributes.AttributesOrder"/>
<exclude name="SlevomatCodingStandard.Files.TypeNameMatchesFileName.NoMatchBetweenTypeNameAndFileName"/>
<exclude name="SlevomatCodingStandard.Classes.EmptyLinesAroundClassBraces.NoEmptyLineAfterOpeningBrace"/>
<exclude name="SlevomatCodingStandard.Functions.DisallowNamedArguments.DisallowedNamedArgument"/>
<exclude name="SlevomatCodingStandard.Functions.RequireTrailingCommaInCall.MissingTrailingComma"/>
<exclude name="SlevomatCodingStandard.Attributes.AttributeAndTargetSpacing.IncorrectLinesCountBetweenAttributeAndTarget"/>
<exclude name="SlevomatCodingStandard.Classes.EmptyLinesAroundClassBraces.NoEmptyLineBeforeClosingBrace"/>
<exclude name="SlevomatCodingStandard.Functions.FunctionLength.FunctionLength"/>
<exclude name="SlevomatCodingStandard.Files.FunctionLength.FunctionLength"/>
<exclude name="SlevomatCodingStandard.Complexity.Cognitive.ComplexityTooHigh"/>
<exclude name="SlevomatCodingStandard.ControlStructures.DisallowNullSafeObjectOperator.DisallowedNullSafeObjectOperator"/>
<exclude name="SlevomatCodingStandard.ControlStructures.NewWithoutParentheses.UselessParentheses"/>
<exclude name="SlevomatCodingStandard.Functions.RequireTrailingCommaInDeclaration.MissingTrailingComma"/>
<exclude name="SlevomatCodingStandard.Namespaces.FullyQualifiedExceptions.NonFullyQualifiedException"/>
<exclude name="SlevomatCodingStandard.Namespaces.FullyQualifiedGlobalFunctions.NonFullyQualified"/>
<exclude name="SlevomatCodingStandard.ControlStructures.DisallowEmpty.DisallowedEmpty"/>
<exclude name="SlevomatCodingStandard.Classes.DisallowConstructorPropertyPromotion.DisallowedConstructorPropertyPromotion"/>
<exclude name="SlevomatCodingStandard.TypeHints.DisallowMixedTypeHint.DisallowedMixedTypeHint"/>
<exclude name="SlevomatCodingStandard.Namespaces.FullyQualifiedGlobalConstants.NonFullyQualified"/>
<exclude name="SlevomatCodingStandard.Exceptions.DisallowNonCapturingCatch.DisallowedNonCapturingCatch"/>
<exclude name="SlevomatCodingStandard.Namespaces.FullyQualifiedClassNameInAnnotation.NonFullyQualifiedClassName"/>
<exclude name="SlevomatCodingStandard.PHP.RequireExplicitAssertion.RequiredExplicitAssertion"/>
<exclude name="SlevomatCodingStandard.Commenting.DisallowOneLinePropertyDocComment.OneLinePropertyComment"/>
<exclude name="SlevomatCodingStandard.ControlStructures.RequireMultiLineTernaryOperator.MultiLineTernaryOperatorNotUsed"/>
<exclude name="SlevomatCodingStandard.Classes.SuperfluousAbstractClassNaming.SuperfluousPrefix"/>
<exclude name="SlevomatCodingStandard.Classes.RequireAbstractOrFinal.ClassNeitherAbstractNorFinal"/>
<exclude name="SlevomatCodingStandard.ControlStructures.DisallowYodaComparison.DisallowedYodaComparison"/>
<exclude name="SlevomatCodingStandard.Classes.TraitUseSpacing.IncorrectLinesCountBeforeFirstUse"/>
<exclude name="SlevomatCodingStandard.PHP.DisallowReference.DisallowedPassingByReference"/>
<exclude name="SlevomatCodingStandard.Arrays.AlphabeticallySortedByKeys.IncorrectKeyOrder"/>
<exclude name="SlevomatCodingStandard.Classes.TraitUseSpacing.IncorrectLinesCountAfterLastUse"/>
<exclude name="SlevomatCodingStandard.Commenting.RequireOneLineDocComment.MultiLineDocComment"/>
<exclude name="SlevomatCodingStandard.ControlStructures.RequireYodaComparison"/>
<exclude name="SlevomatCodingStandard.ControlStructures.EarlyExit"/>
<exclude name="SlevomatCodingStandard.ControlStructures.BlockControlStructureSpacing.IncorrectLinesCountAfterControlStructure"/>
<exclude name="SlevomatCodingStandard.ControlStructures.JumpStatementsSpacing.IncorrectLinesCountBeforeControlStructure"/>
<exclude name="SlevomatCodingStandard.ControlStructures.BlockControlStructureSpacing.IncorrectLinesCountBeforeControlStructure"/>
<exclude name="SlevomatCodingStandard.Functions.DisallowArrowFunction.DisallowedArrowFunction"/>
<exclude name="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingNativeTypeHint"/>
<exclude name="SlevomatCodingStandard.Arrays.TrailingArrayComma.MissingTrailingComma"/>
<exclude name="SlevomatCodingStandard.ControlStructures.UselessIfConditionWithReturn.UselessIfCondition"/>
</rule>
</ruleset>
Run
vendor/bin/phpcs -s --standard=phpcs_ruleset.xml src
PHP Coding Standards Fixer
Installation
composer require --dev friendsofphp/php-cs-fixer
Run
vendor/bin/php-cs-fixer fix --dry-run --diff -v src
PHPMD
Installation
composer require --dev phpmd/phpmd
Configuration
src/phpmd_ruleset.xml<?xml version="1.0"?>
<ruleset name="PHPMD rule set"
xmlns="http://pmd.sf.net/ruleset/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0
http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:noNamespaceSchemaLocation="
http://pmd.sf.net/ruleset_xml_schema.xsd">
<description></description>
<rule ref="rulesets/cleancode.xml">
<exclude name="StaticAccess" />
<exclude name="BooleanArgumentFlag" />
<exclude name="ElseExpression" />
</rule>
<rule ref="rulesets/design.xml">
<exclude name="CouplingBetweenObjects" />
<exclude name="EmptyCatchBlock" />
</rule>
<rule ref="rulesets/naming.xml">
<exclude name="ShortVariable" />
<exclude name="LongVariable" />
<exclude name="LongClassName" />
</rule>
<rule ref="rulesets/unusedcode.xml">
<exclude name="UnusedFormalParameter" />
</rule>
</ruleset>
Run
# apk add jq
# or
# apt-get install jq
vendor/bin/phpmd src json phpmd_ruleset.xml | jq