Skip to content

Latest commit

 

History

History
305 lines (262 loc) · 26.8 KB

File metadata and controls

305 lines (262 loc) · 26.8 KB

PHP coding standards

We adopted the standards for programming in PHP from PSR-12. We enforce these standards by using tools like PHPCS and PHP Phan

PHP best practides

We follow the best practices compiled under PSR12 and PHP - the right way

Security Standards

We follow security practices outlined by OSWAP Cheat Series while building the applications using PHP.

Enforcing tools and config

PHPCS

Installation

composer require squizlabs/php_codesniffer --dev

PHPCS by default comes with a set of rules which can snif your code against popular standards like PSR1, PSR12 etc. Among the default rules, we use the following rules

Rule Description URL
PSR12 Checks for PSR standards Link
PSR12.Files.FileHeader.SpacingAfterBlock To exclude checking the format of the file header. Link
Generic.PHP.RequireStrictTypes Checks for strict type on each file Link
Zend.NamingConventions.ValidVariableName Checks the naming of variables and member variables. Link

To install and include external snifs which are created by reliable resources such as slemovat, add the following to the config -

composer require slevomat/coding-standard --dev
<config name="installed_paths" value="../../slevomat/coding-standard"/>
Rule Description URL
SlevomatCodingStandard.TypeHints.UselessConstantTypeHint Checks for useless constant type hints in function and method signatures. Link
SlevomatCodingStandard.Arrays.DisallowImplicitArrayCreation Disallows implicit array creation using the short syntax [] and requires using the explicit array() syntax. Link
SlevomatCodingStandard.ControlStructures.RequireNullCoalesceOperator Enforces the use of the null coalesce operator (??) instead of the ternary operator (?:) when checking for null values. Link
SlevomatCodingStandard.PHP.UselessSemicolon Detects and removes useless semicolons in PHP code. Link
SlevomatCodingStandard.Variables.UnusedVariable Detects unused variables and raises warnings to encourage their removal. Link
SlevomatCodingStandard.Variables.UselessVariable Detects and removes useless variables that are assigned but never used. Link
SlevomatCodingStandard.Exceptions.DeadCatch Detects dead catch blocks in try-catch statements where an exception type is caught but not used. Link
SlevomatCodingStandard.Classes.MethodSpacing Enforces a consistent spacing between methods in PHP classes. Link
SlevomatCodingStandard.Classes.PropertySpacing Enforces a consistent spacing between properties in PHP classes. Link
SlevomatCodingStandard.Namespaces.UnusedUses Detects unused import statements (use statements) in PHP namespaces and suggests their removal. Link
SlevomatCodingStandard.Namespaces.AlphabeticallySortedUses Enforces alphabetically sorted import statements (use statements) in PHP namespaces. Link
SlevomatCodingStandard.Whitespaces.DuplicateSpaces Detects duplicate spaces in PHP code and suggests their removal. Link
SlevomatCodingStandard.TypeHints.ReturnTypeHintSpacing Enforces a consistent spacing around the return type hints in PHP function and method signatures. Link
SlevomatCodingStandard.Commenting.DisallowCommentAfterCode Disallows comments placed after code statements and encourages placing comments on a separate line. Link
SlevomatCodingStandard.Commenting.EmptyComment Detects and removes empty comments in PHP code. Link
SlevomatCodingStandard.Commenting.RequireOneLineDocComment Enforces the use of one-line doc comments for properties, constants, and methods in PHP classes. Link
SlevomatCodingStandard.ControlStructures.UselessIfConditionWithReturn Detects and removes unnecessary if conditions in PHP code where a return statement follows immediately. Link
SlevomatCodingStandard.ControlStructures.UselessTernaryOperator Detects and suggests removing unnecessary ternary operators in PHP code where the condition is redundant. Link
SlevomatCodingStandard.TypeHints.ReturnTypeHint Checks for missing return typehints in case they can be declared natively. Link
SlevomatCodingStandard.TypeHints.ParameterTypeHint Checks for missing parameter typehints in case they can be declared natively. Link
SlevomatCodingStandard.TypeHints.PropertyTypeHint Checks for missing property typehints in case they can be declared natively. Link

Configuration

<?xml version="1.0"?>
<ruleset name="PHP_CodeSniffer">
    <!-- Include the following directories for violation check -->
    <file>folder1</file>
    <file>folder2</file>

    <!-- Exclude our migrations directory from the violation check-->
    <exclude-pattern>*/vendor/*</exclude-pattern>
	<arg name="tab-width" value="4"/>
    
    <!-- Include PSR12 standards -->
	<rule ref="PSR12">
        <exclude name="PSR12.Files.FileHeader.SpacingAfterBlock"/>
	</rule>	
    <rule ref="Generic.PHP.RequireStrictTypes" />
    <!-- Variable naming standards -->
    <rule ref="Zend.NamingConventions.ValidVariableName" />
	
	<!-- See https://github.com/slevomat/coding-standard#sniffs-included-in-this-standard -->
	<config name="installed_paths" value="../../slevomat/coding-standard"/>
	<rule ref="SlevomatCodingStandard.TypeHints.UselessConstantTypeHint" />
	<rule ref="SlevomatCodingStandard.Arrays.DisallowImplicitArrayCreation" />
	<rule ref="SlevomatCodingStandard.ControlStructures.RequireNullCoalesceOperator" />
	<rule ref="SlevomatCodingStandard.PHP.UselessSemicolon" />
	<rule ref="SlevomatCodingStandard.Variables.UnusedVariable">
		<properties>
			<property name="ignoreUnusedValuesWhenOnlyKeysAreUsedInForeach" value="true" />
		</properties>
	</rule>
	<rule ref="SlevomatCodingStandard.Variables.UselessVariable" />
	<rule ref="SlevomatCodingStandard.Exceptions.DeadCatch" />
	<rule ref="SlevomatCodingStandard.Classes.MethodSpacing" >
		<properties>
			<property name="minLinesCount" value="1"/>
			<property name="maxLinesCount" value="1"/>
		</properties>
	</rule>
	<rule ref="SlevomatCodingStandard.Classes.PropertySpacing">
		<properties>
			<property name="minLinesCountBeforeWithComment" value="0"/>
			<property name="maxLinesCountBeforeWithComment" value="0"/>
			<property name="minLinesCountBeforeWithoutComment" value="0"/>
			<property name="maxLinesCountBeforeWithoutComment" value="0"/>
		</properties>
	</rule>
	<rule ref="SlevomatCodingStandard.Namespaces.UnusedUses">
		<properties>
			<property name="searchAnnotations" value="true"/>
		</properties>
	</rule>
	<rule ref="SlevomatCodingStandard.Namespaces.AlphabeticallySortedUses" />
	<rule ref="SlevomatCodingStandard.Whitespaces.DuplicateSpaces" />
	<rule ref="SlevomatCodingStandard.TypeHints.ReturnTypeHintSpacing">
		<properties>
			<property name="spacesCountBeforeColon" value="0"/>
		</properties>
	</rule>
	<rule ref="SlevomatCodingStandard.Commenting.DisallowCommentAfterCode" />
	<rule ref="SlevomatCodingStandard.Commenting.EmptyComment" />
	<rule ref="SlevomatCodingStandard.Commenting.RequireOneLineDocComment" />
	<rule ref="SlevomatCodingStandard.ControlStructures.UselessIfConditionWithReturn" />
	<rule ref="SlevomatCodingStandard.ControlStructures.UselessTernaryOperator" />

    <!-- disable useless function comment -->
    <rule ref="SlevomatCodingStandard.Commenting.UselessFunctionDocComment" />
    <!-- For PHP Type checks -->
    <rule ref="SlevomatCodingStandard.TypeHints.ReturnTypeHint" />
    <rule ref="SlevomatCodingStandard.TypeHints.ParameterTypeHint" />
    <rule ref="SlevomatCodingStandard.TypeHints.PropertyTypeHint" />    
</ruleset>

Usage

Create a file with name phpcs.xml in the project root directory. Copy the configuration details from above section and place in the created file. Make the necessary changes about the inlusion/exclusion folders.

Add couple of script commands to run phpcs and phpcbf in composer.json file.

"scripts": {
    // ..<existing scripts>
    "lint": "vendor/bin/phpcs --standard=.phpcs.xml",
    "lint:fix": "vendor/bin/phpcbf --standard=.phpcs.xml",
  },

composer run lint

This command will tokenize PHP files to detect violations of a defined coding standard.

composer run lint:fix

This command will automatically correct coding standard violations.

PHP PHAN

Installation

composer require phan/phan --dev

Inorder to let your project use PHP Phan, you have to create a folder .phan and a file in it config.php. All the settings for phan are placed there. Here are some key settings to be added -

Setting Description URL
target_php_version Set the PHP version of your project. Link
directory_list Directory list that should be checked for violations. Link
exclude_analysis_directory_list Directory list that will be skipped to check violations. Link
plugins A list of plugin files to execute. Link
suppress_issue_types Inhibits some issues which don't matter much. Link
backward_compatibility_checks Backwards Compatibility Checking. It consumes a lot of memory, do only if necessary. Link
unused_variable_detection Set to true in order to attempt to detect unused variables. Link

All the phan settings can be found here PHP Phan works with plugins which comes along while installing it. Here are some plugins that we use

Plugin Description URL
AlwaysReturnPlugin Checks if a function or method with a non-void return type will unconditionally return or throw Link
DollarDollarPlugin Checks for complex variable access expressions $$x Link
DuplicateArrayKeyPlugin Warns about common errors in PHP array keys and switch statements Link
DuplicateExpressionPlugin Checks for duplicate expressions in a statement that are likely to be a bug Link
PregRegexCheckerPlugin This plugin checks for invalid regexes Link
PrintfCheckerPlugin Checks for invalid format strings, incorrect argument counts, and unused arguments in printf calls Link
SleepCheckerPlugin Warn about returning non-arrays in __sleep, as well as about returning array values with invalid property names in __sleep Link
UnreachableCodePlugin Checks for syntactically unreachable statements in the global scope or function bodies Link
UseReturnValuePlugin This warns when code fails to use the return value of internal functions/methods Link
EmptyStatementListPlugin Checks for empty statement lists in loops/branches Link
LoopVariableReusePlugin This plugin detects reuse of loop variables Link

All the PHP Phan plugins are documented here

Configuration

<?php

/**
 * This configuration will be read and overlaid on top of the
 * default configuration. Command line arguments will be applied
 * after this file is read.
 */
return [

    // Supported values: `'5.6'`, `'7.0'`, `'7.1'`, `'7.2'`, `'7.3'`, `'7.4'`,
    // `'8.0'`, `'8.1'`, `null`.
    // If this is set to `null`,
    // then Phan assumes the PHP version which is closest to the minor version
    // of the php executable used to execute Phan.
    "target_php_version" => '8.1',

    // A list of directories that should be parsed for class and
    // method information. After excluding the directories
    // defined in exclude_analysis_directory_list, the remaining
    // files will be statically analyzed for errors.
    //
    // Thus, both first-party and third-party code being used by
    // your application should be included in this list.
    
    // Note - Keep adding to the vendor section below as we add more dependencies
    // based on the errors you encounter when you run phan. 
    
    'directory_list' => [
        'folder'
    ],

    // A directory list that defines files that will be excluded
    // from static analysis, but whose class and method
    // information should be included.
    //
    // Generally, you'll want to include the directories for
    // third-party code (such as "vendor/") in this list.
    //
    // n.b.: If you'd like to parse but not analyze 3rd
    //       party code, directories containing that code
    //       should be added to the `directory_list` as
    //       to `exclude_analysis_directory_list`.
    "exclude_analysis_directory_list" => [
        'vendor'
    ],

    // A list of plugin files to execute.
    // Plugins which are bundled with Phan can be added here by providing their name
    // (e.g. 'AlwaysReturnPlugin')
    //
    // Documentation about available bundled plugins can be found
    // at https://github.com/phan/phan/tree/v5/.phan/plugins
    //
    // Alternately, you can pass in the full path to a PHP file
    // with the plugin's implementation.
    // (e.g. 'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php')
    'plugins' => [
        // checks if a function, closure or method unconditionally returns.
        // can also be written as 'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php'
        'AlwaysReturnPlugin',
        'DollarDollarPlugin',
        'DuplicateArrayKeyPlugin',
        'DuplicateExpressionPlugin',
        'PregRegexCheckerPlugin',
        'PrintfCheckerPlugin',
        'SleepCheckerPlugin',
        // Checks for syntactically unreachable statements in
        // the global scope or function bodies.
        'UnreachableCodePlugin',
        'UseReturnValuePlugin',
        'EmptyStatementListPlugin',
        'LoopVariableReusePlugin',
    ],
    'suppress_issue_types' => [
		// The following two have been added to not highlight issues
		// raised due to variables added for interface methods that are
		// then not used by the interface implementation
		'PhanUnusedPublicMethodParameter',
		'PhanUnusedProtectedMethodParameter',
		'PhanUnusedPrivateMethodParameter',
		// Allow unused values in foreach
		'PhanUnusedVariableValueOfForeachWithKey'		
	],
	// Backwards Compatibility Checking
	// (Disable this if the application no longer supports php 5,
	// or use a different tool.
	// Phan's checks are currently slow)
	// Set it to false or omit it.
	'backward_compatibility_checks' => false,
	'unused_variable_detection' => true
];

Usage

Create a directory .phanand a file inside it config.php in the project root directory. Copy the configuration details from above section and place in the created file. Make the necessary changes regarding the inlusion/exclusion of folders.

Add script command to run phan in composer.json file.

"scripts": {
    // ..<existing scripts>
    "phan": "vendor/bin/phan --config-file .phan/config.php",
  },

composer run phan

This command will analyze and display all the issues if any.