Notes on software development

How to create a PHP package. Part 3: Code style

This is the third part of a series on creating a PHP package. In the previous parts, we created a project and covered it with tests.

This time we will implement a code style check to sure that our code not only works correctly but follows the style requirements. This is especially useful when working in a team and all members follow requirements.

1. Installing PHP_CodeSniffer

There are a number of libraries for style checking. We will use the popular PHP_CodeSniffer library, which not only can detect code style violations but also, if necessary, correct them automatically.

Let's install this library as a dev dependency using the composer:

composer require --dev doctrine/coding-standard

By default PHP_CodeSniffer uses the PEAR coding standard. Let's check our file for violations:

./vendor/bin/phpcs src/Highlighter.php

Or check the entire folder:

./vendor/bin/phpcs src

If you copied the code from the example, then most likely, there will be no style violations, because I checked it beforehand. You can try to add some formatting errors to sure the validation works. You can also choose which requirements to follow, for example, check the formatting according to the PSR-12 coding standard:

./vendor/bin/phpcs --standard=PSR12 src

2. Configuring PHP_CodeSniffer with XML

PHP_CodeSniffer also allows you to create your own rulesets as an XML file or make changes to existing rulesets.

Let's configure PHP_CodeSniffer to our needs.

At the root folder create a phpcs.xml.dist file, which will describe the rules, and implement the Doctrine Coding Standard, which in turn relies on the Slevomat Coding Standard for PHP_CodeSniffer:

composer require --dev slevomat/coding-standard

Below the example of a configuration file:

<?xml version="1.0"?>
<ruleset>
    <arg name="basepath" value="."/>
    <arg name="extensions" value="php"/>
    <arg name="parallel" value="80"/>
    <arg name="cache" value=".phpcs-cache"/>
    <arg name="colors"/>

    <!-- Ignore warnings, show progress of the run and show sniff names -->
    <arg value="nps"/>

    <!-- Directories to be checked -->
    <file>examples</file>
    <file>src</file>
    <file>tests</file>

    <!-- Include full Doctrine Coding Standard -->
    <rule ref="Doctrine">
        <exclude name="SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing"/>
        <exclude name="SlevomatCodingStandard.TypeHints.UnionTypeHintFormat.DisallowedShortNullable"/>
        <exclude name="SlevomatCodingStandard.TypeHints.ParameterTypeHintSpacing.MultipleSpacesBetweenTypeHintAndParameter"/>
        <exclude name="SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly.ReferenceViaFallbackGlobalName"/>
        <exclude name="SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly.ReferenceViaFullyQualifiedName"/>
        <exclude name="SlevomatCodingStandard.Variables.UselessVariable.UselessVariable"/>
        <exclude name="SlevomatCodingStandard.Classes.UnusedPrivateElements.UnusedMethod"/>
        <exclude name="SlevomatCodingStandard.Classes.PropertyDeclaration.MultipleSpacesBetweenTypeHintAndProperty"/>
        <exclude name="SlevomatCodingStandard.Classes.SuperfluousExceptionNaming.SuperfluousSuffix"/>
        <exclude name="SlevomatCodingStandard.Commenting.RequireOneLineDocComment.MultiLineDocComment"/>
        <exclude name="SlevomatCodingStandard.ControlStructures.EarlyExit.EarlyExitNotUsed"/>
        <exclude name="SlevomatCodingStandard.PHP.RequireExplicitAssertion.RequiredExplicitAssertion"/>
        <exclude name="Generic.Formatting.SpaceAfterNot.Incorrect"/>
        <exclude name="Generic.Formatting.MultipleStatementAlignment.NotSame"/>
        <exclude name="Squiz.Functions.FunctionDeclarationArgumentSpacing.SpacingAfterHint"/>
        <exclude name="Squiz.Functions.MultiLineFunctionDeclaration.NewlineBeforeOpenBrace"/>
    </rule>

    <exclude-pattern>examples/</exclude-pattern>
</ruleset>

You can find documentation on the configuration file here.

As you see, we can set which folders to scan, which to exclude, and also exclude some rules.

Let's now run the style code check again:

./vendor/bin/phpcs

Let's add this command to the composer into scripts section:

"scripts": {
    ...,
    "linter": "./vendor/bin/phpcs"
}

Now we can run this script with the command:

composer linter

Please note that it is not necessary to follow all the rules, you can exclude some if you think they are redundant.

The style code rules allow you to keep a consistent style for the entire project. Which rules to choose and follow depends on the team members themselves.

What's next?

This time we added and configured the code style check using PHP_CodeSniffer. Next, we will create a repository on Github, deal with versioning, tagging and others.

 
Комментарии