r76568 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r76567‎ | r76568 | r76569 >
Date:11:16, 12 November 2010
Author:hashar
Status:deferred
Tags:
Comment:
Basic script to find out long functions or methods in a PHP file.
Modified paths:
  • /trunk/tools/code-utils/find-long-functions.php (added) (history)

Diff [purge]

Index: trunk/tools/code-utils/find-long-functions.php
@@ -0,0 +1,186 @@
 2+<?php
 3+/**
 4+ * T_WHITESPACE \t \r\n
 5+ * T_FUNCTION
 6+ * T_ENDDECLARE
 7+ * T_DECLARE
 8+ * 0 : token index
 9+ * 1 : content
 10+ * 2 : line number
 11+ *
 12+ * @param $token_array An array of tokens as returned by PHP token_get_all()
 13+ */
 14+function _analyze_tokens( $token_array ) {
 15+ $state = array(
 16+ 'function' => '', # function name
 17+ 'fdepth' => null, # function depth in the brace hierarchy
 18+ 'fstart_line' => 0, # function declaration start line
 19+
 20+ 'class' => '', # class name
 21+ 'cdepth' => null, # class depth in the brace hierarchy
 22+ 'cstart_line' => 0, # class declaration start line
 23+
 24+ 'cur_line' => 0, # current line analyzed
 25+ 'line' => 0, # line number
 26+ 'depth' => 0, # braces depth
 27+ );
 28+
 29+ $tokens = new TokenIterator( $token_array );
 30+ $tokens->rewind();
 31+
 32+ // loop while we get tokens from the iterator
 33+ while( $tokens->valid() ) {
 34+ $token = $tokens->current();
 35+
 36+ # handles braces returned by token_get_all() as strings
 37+ if( is_string( $token ) ) {
 38+ if( $token == '{' ) {
 39+ $state['depth']++;
 40+ } elseif( $token == '}' ) {
 41+ $state['depth']--;
 42+ if( $state['depth'] === $state['cdepth'] ) {
 43+ $l = $state['cur_line'] - $state['cstart_line'];
 44+ print "Done with class {$state['class']}, $l lines long.\n\n";
 45+ $state['class'] = '';
 46+ $state['cdepth'] = null;
 47+ $state['cstart_line'] = null;
 48+ } elseif( $state['depth'] === $state['fdepth'] ) {
 49+ $l = $state['cur_line'] - $state['fstart_line'];
 50+ printf( "%5s lines for %s.\n", $l, $state['function'] );
 51+ $state['function'] = '';
 52+ $state['fdepth'] = null;
 53+ $state['fstart_line'] = null;
 54+ }
 55+ } else { print "Got unwanted string: $token\n"; }
 56+
 57+ debug_state( $state, $token );
 58+
 59+ $tokens->next();
 60+ continue;
 61+ }
 62+
 63+ $state['cur_line'] = $token[2];
 64+
 65+ # handles CLASS and FUNCTION tokens
 66+ switch( $token[0] ) {
 67+ case T_CURLY_OPEN:
 68+ $state['depth']++;
 69+ break;
 70+ case T_CLASS:
 71+ case T_FUNCTION:
 72+ # find the token giving function or class name
 73+ $name_token = $tokens->nextOfKind( T_STRING );
 74+
 75+ if( $token[0] == T_CLASS ) {
 76+ $TYPE = 'class';
 77+ $state['cdepth'] = $state['depth'];
 78+ $state['cstart_line'] = $state['cur_line'];
 79+ $state['class'] = $name_token[1];
 80+ print "Analyzing class {$state['class']}\n";
 81+ } else {
 82+ $TYPE = 'function';
 83+ $state['fdepth'] = $state['depth'];
 84+ $state['fstart_line'] = $state['cur_line'];
 85+ if( $state['class'] ) {
 86+ $state['function'] = $state['class'] . '::' . $name_token[1];
 87+ } else {
 88+ $state['function'] = $name_token[1];
 89+ }
 90+ }
 91+
 92+ default:
 93+ debug_state( $state, $token );
 94+ }
 95+
 96+ $tokens->next();
 97+ }
 98+}
 99+
 100+/**
 101+ * Debugging function used to output a token position in the brace hierarchy
 102+ */
 103+function debug_state( $state, $token = null ) {
 104+ return;
 105+ printf( "cdepth: %s, fdepth: %s, depth: %s | ",
 106+ $state['cdepth'],
 107+ $state['fdepth'],
 108+ $state['depth']
 109+ );
 110+ if( is_array( $token ) ) {
 111+ printf( "line %s - %s: %s\n", $token[2], token_name( $token[0] ), $token[1] );
 112+ } else {
 113+ print "string $token\n";
 114+ }
 115+}
 116+
 117+/**
 118+ * A basic iterator extending the PHP ArrayIterator class.
 119+ */
 120+class TokenIterator extends ArrayIterator {
 121+ function __construct( $array ) {
 122+ parent::__construct( $array );
 123+ }
 124+
 125+ /**
 126+ * Skip tokens until we reach the wanted token. Return it.
 127+ */
 128+ function nextOfKind( $wanted_token_index ) {
 129+ $found = false;
 130+ while( true ) {
 131+ $this->next();
 132+ $token = $this->current();
 133+ if( $token[0] == $wanted_token_index ) {
 134+ return $token;
 135+ }
 136+ }
 137+ }
 138+}
 139+
 140+// We just keep blocks
 141+$wanted_tokens = array( T_FUNCTION, T_STRING, T_CLASS, T_IF, T_WHILE, T_SWITCH, T_CURLY_OPEN );
 142+$wanted_strings = array( '{', '}' );
 143+$unwanted_tokens = array( T_WHITESPACE );
 144+
 145+/**
 146+ * Callback used to get ride of unneeded tokens.
 147+ * @param mixed A PHP Token
 148+ * @return Boolean Whether to keep the token
 149+ */
 150+function _filter( $token ) {
 151+ global $wanted_tokens, $wanted_strings, $unwanted_tokens ;
 152+ if( false && is_array( $token ) ) {
 153+ return in_array( $token[0] , $wanted_tokens );
 154+ }
 155+ if( is_array( $token ) ) {
 156+ return !in_array( $token[0] , $unwanted_tokens );
 157+ }
 158+ if( is_string( $token ) ) {
 159+ return in_array( $token, $wanted_strings );
 160+ }
 161+ return true;
 162+}
 163+
 164+function analyze_file( $file ) {
 165+ $content = file_get_contents( $file );
 166+ if( $content === false ) {
 167+ print "Could not open file $file\n";
 168+ return null;
 169+ }
 170+
 171+ $tokens = token_get_all( $content );
 172+ $tokens = array_filter( $tokens, '_filter' );
 173+ _analyze_tokens( $tokens );
 174+}
 175+
 176+
 177+# Print usage when no source file given
 178+if( $argc == 1 ) {
 179+ die( "Usage: $argv[0] <PHP_source_file>\n" );
 180+}
 181+array_shift( $argv ); // skip script name
 182+
 183+# Parse each file given as an argument, one after the other...
 184+foreach( $argv as $arg ) {
 185+ print "Trying file $arg...\n";
 186+ analyze_file( $arg );
 187+}

Follow-up revisions

RevisionCommit summaryAuthorDate
r76574Followup r76568, svn:eol-style native. C'mmonn!reedy13:34, 12 November 2010

Status & tagging log