Detecting Code Smells In Php

last modified: October 23, 2003

Here's some code to detect a few code smells in a PHP file. It can be easily adapted to detect code smells in C, C++, Java, etc. code.

$MAX_INDENTATION_LEVEL = 3;
$MAX_FUNCTION_LINE_COUNT = 20;
$MAX_NUM_PARAMETERS = 4;



function print_warning( $filename, $line, $line_number, $warning )
  {
  print( "<code>$filename</code>: <strong>$warning</strong><br />\n" .
         "&nbsp; &nbsp; Line $line_number: <code>$line</code><br />\n" );
  }



function test_line_for_indentation( $line, $max_indentation_level )
  {
  $char_posit = 0;
  while( substr( $line, $char_posit, 1 ) == "\t" )
    $char_posit++;
  if( $char_posit > $max_indentation_level )
    return false;
  return true;
  }



function test_line_for_function_definition( $line, $max_num_parameters )
  {
  if( substr( $line, 0, 9 ) == "function " )
    {
    if( substr_count( $line, ',' ) >= $max_num_parameters )
      return false;
    }
    return true;
  }



function test_file_for_smells( $filename )
  {
  global $MAX_FUNCTION_LINE_COUNT, $MAX_INDENTATION_LEVEL;
  $function_line_count = 0;
  $found_continued_line = 0;
  $line_number = 0;
  $fp = fopen( $filename, "r" );
  if( ! $fp )
    return;
  while( ! feof( $fp ) )
    {
    $line = chop( fgets( $fp, 4096 ) );
    $line_number++;
    while( substr( $line, 0, 9 ) == "function "  &&
           substr( $line, strlen($line) - 1, 1 ) != ')' )
      {
      $line = $line . chop( fgets( $fp, 4096 ) )
      $found_continued_line++;
      }
    if( substr( $line, 0, 9 ) == "function " )
      {
      $function_line_count = 1;
      $function_name = substr( $line, 9, strpos($line, '(') - 9 );
      }
    if( $function_line_count > 0 )
      {
      if( $line == "\t}" )
        {
        $function_line_count = $function_line_count - 3;
        if( $function_line_count > $MAX_FUNCTION_LINE_COUNT )
          print_warning( $filename, $line, $line_number, "$function_name() too long ($function_line_count lines)" );
        $function_line_count = 0;
        }
      else
        $function_line_count++;
      $result = test_line_for_indentation( $line, $MAX_INDENTATION_LEVEL );
      if( ! $result )
        print_warning( $filename, $line, $line_number, "Too much nesting." );
      $result = test_line_for_function_definition( $line, $MAX_NUM_PARAMETERS );
      if( ! $result )
        print_warning( $filename, $line, $line_number, "Too many parameters." );
      if( $found_continued_line > 0 )
        {
        $line_number += $found_continued_line;
        $found_continued_line = 0;
        }
      }
    }
  }

Please feel free to ReFactor this code. test_file_for_smells() would fail its own tests! -- BrentNewhall

Doesn't this assume tabs are always used for indentation?

This code probably needs to be refactored to use the tokenizer extension. I have a "CodeSmeller" object written in PHP5, I will post it soon. -- JonathanArkell


CategoryPhp


Loading...