Search code examples
phpemacsstatic-analysisphpcodesniffer

How to configure PHP CodeSniffer to allow my case statements to be indented the way I like?


I have code that looks like this:

function processRequest() {

  // get the verb
  $method = strtolower($_SERVER['REQUEST_METHOD']);

  switch ($method) {
    case 'get':
      handleGet();
      break;
    case 'post':
      handlePost();
      // $data = $_POST;
      break;
    case 'delete':
      handleDelete();
      break;
    case 'options':
      header('Allow: GET, POST, DELETE, OPTIONS');
      break;
    default:
      header('HTTP/1.1 405 Method Not Allowed');
      break;
  }
}

PHP CodeSniffer complains about the indents of those case statements. In emacs with flymake it looks like this:

enter image description here

The message is:

error - Line indented incorrectly; expected 2 spaces, found 4 (PEAR.WhiteSpace.ScopeIndent.Incorrect)

Obviously CodeSniffer wants the case statements to be LESS indented than they are.

How can I tell CodeSniffer to allow my case statements to be indented the way I want them. Or better, to enforce that my case statements are indented this way?


Solution

  • The Sniff known as PEAR.Whitespace.ScopeIndent is defined in code file phpcs\CodeSniffer\Standards\PEAR\Sniffs\Whitespace\ScopeIndentSniff.php and includes the following code:

    class PEAR_Sniffs_WhiteSpace_ScopeIndentSniff extends Generic_Sniffs_WhiteSpace_ScopeIndentSniff
    {
        /**
         * Any scope openers that should not cause an indent.
         *
         * @var array(int)
         */
        protected $nonIndentingScopes = array(T_SWITCH);
    
    }//end class
    

    See the $nonIndentingScopes? It apparently means that anything within the scope of a switch statement is expected to not be indented with respect to the scope-opening curly.

    I could not find a way to tweak this setting in PEAR.Whitespace.ScopeIndent, but.... that Sniff extends the more basic Generic.Whitespace.ScopeIndent, which does not include T_SWITCH in the $nonIndentingScopes array.

    So what I did to allow my case statements the way I wanted was to modify my ruleset.xml file, to exclude the PEAR version of that sniff, and include the Generic version of that sniff. It looks like this:

    <?xml version="1.0"?>
    <ruleset name="Custom Standard">
      <!-- http://pear.php.net/manual/en/package.php.php-codesniffer.annotated-ruleset.php -->
      <description>My custom coding standard</description>
    
      <rule ref="PEAR">
             ......
        <exclude name="PEAR.WhiteSpace.ScopeIndent"/>
      </rule>
    
       ....
    
      <!-- not PEAR -->
      <rule ref="Generic.WhiteSpace.ScopeIndent">
        <properties>
          <property name="indent" value="2"/>
        </properties>
      </rule>
    
    </ruleset>
    

    This file needs to be present in a subdir under the Standards directory for PHP CodeSniffer. For me, the file location is \dev\phpcs\CodeSniffer\Standards\MyStandard\ruleset.xml

    Then I run phpcs like this:

    \php\php.exe \dev\phpcs\scripts\phpcs --standard=MyStandard --report=emacs -s file.php