PHP Classes

File: phpcf-src/test/expected/phpcf.php

Recommend this page to a friend!
  Classes of Alex Krash   PHP Code formatter   phpcf-src/test/expected/phpcf.php   Download  
File: phpcf-src/test/expected/phpcf.php
Role: Unit test script
Content type: text/plain
Description: Unit test script
Class: PHP Code formatter
Reformat PHP code according to standard options
Author: By
Last change:
Date: 9 years ago
Size: 81,547 bytes
 

Contents

Class file image Download
#!/local/php5/bin/php <?php define('PHPCF_KEY_ALL', 1); define('PHPCF_KEY_LEFT', 2); define('PHPCF_KEY_RIGHT', 3); define('PHPCF_KEY_TYPE', 4); define('PHPCF_KEY_CODE', 5); define('PHPCF_KEY_TEXT', 6); define('PHPCF_KEY_LINE', 7); define('PHPCF_KEY_SEQUENCE', 8); define('PHPCF_KEY_TOKEN_LENGTH', 9); define('PHPCF_KEY_DESCR_LEFT', 10); define('PHPCF_KEY_DESCR_RIGHT', 11); /*************************************************************************************************/ /* PHPCF_EX-constants - special PHPCF_EXecutors processed at final output stage /* Note, that order is important -- first executor has higher priority than the last /* - DELETE: just delete, nuff said /* - SHRINK: shrink to a single token /* - CHECK: just check, if not exists - add, but don't shrink /* - INCREASE/DECREASE: indent operations /*************************************************************************************************/ $cnt = 100; define('PHPCF_EX_DO_NOT_TOUCH_ANYTHING', $cnt++); define('PHPCF_EX_CHECK_NL_STRONG', $cnt++); define('PHPCF_EX_DELETE_SPACES_STRONG', $cnt++); define('PHPCF_EX_SHRINK_SPACES_STRONG', $cnt++); define('PHPCF_EX_SHRINK_NLS_STRONG', $cnt++); define('PHPCF_EX_SHRINK_NLS_2', $cnt++); // shrink to two lines (if any) define('PHPCF_EX_SHRINK_NLS', $cnt++); define('PHPCF_EX_CHECK_NL', $cnt++); define('PHPCF_EX_DELETE_SPACES', $cnt++); define('PHPCF_EX_SHRINK_SPACES', $cnt++); define('PHPCF_EX_NL_OR_SPACE', $cnt++); // accept either new line or space as whitespace unset($cnt); define('PHPCF_EX_INCREASE_INDENT', 200); define('PHPCF_EX_DECREASE_INDENT', 201); define('PHPCF_CTX_NOW', 'CTX_NOW'); define('PHPCF_CTX_NEXT', 'CTX_NEXT'); // constant is used to determine whether or not need to split expression to several lines define('PHPCF_LONG_EXPRESSION_LENGTH', 120); if (!ini_get('short_open_tag')) { // otherwise short tags will not be tokenized trigger_error('short_open_tag must be enabled for tokenization to work'); } mb_internal_encoding('UTF-8'); if (is_callable('dl')) { if (!function_exists('posix_isatty')) @dl('posix.so'); if (!function_exists('pcntl_fork')) @dl('pcntl.so'); } if (!function_exists('posix_isatty')) { function posix_isatty() { return false; } } class PHPCodeFSM { public $rules = array(); public $state = null; public $state_stack = array(); public $old_state = null; public $prev_code = null; public $current_rules = array(/* state, code_key, rules */); private $delayed_rule = null; public function __construct($rules) { if (!empty($rules)) { foreach ($rules as $key => $data) { $parts = explode(' ', $key); if (empty($parts)) $parts = array($key); foreach ($parts as $key_sub) { $this->rules[$key_sub] = $data; } } if (isset($rules[0])) { $this->state = $rules[0]; } } } public function getState() { return $this->state; } public function getStackPath() { $result = $this->state_stack; $result[] = $this->state; return implode(' / ', $result); } public function transit($code) { if ($code == 'T_WHITESPACE') { return; } $i_rules = false; $code_key = $code; if (isset($this->delayed_rule)) { if (PHPCF_DEBUG) { echo "Found delayed rule: " . print_r($this->delayed_rule, true); echo " in current state: {$this->state}\n"; } $this->state = $this->delayed_rule; $this->executeTransition(); $this->delayed_rule = null; } if (isset($this->rules[$this->state])) { $i_rules = $this->rules[$this->state]; if (!isset($i_rules[$code_key])) { $code_key = PHPCF_KEY_ALL; } if (!empty($i_rules[$code_key])) { $this->current_rules = array($this->state, $code); $this->old_state = $this->state; $this->state = $i_rules[$code_key]; // you can specify delayed context switch as // array(PHPCF_CTX_NOW => ..., PHPCF_CTX_NEXT => ...) if (is_array($this->state) && isset($this->state[PHPCF_CTX_NOW])) { if (isset($this->state[PHPCF_CTX_NEXT])) { $this->delayed_rule = $this->state[PHPCF_CTX_NEXT]; } $this->state = $this->state[PHPCF_CTX_NOW]; } $this->executeTransition(); } } $this->prev_code = $code; } private function executeTransition() { if (is_array($this->state)) { // context inside context $this->state = $this->state[0]; $this->state_stack[] = $this->old_state; } elseif ($this->state < 0) { $i = -$this->state; while ($i > 0) { $this->state = array_pop($this->state_stack); $i--; } } } } class PHPCodeFormatter { private $tokens = array(); public $FSM = null; public $sniff_exit_code = 0; private $exec = array(); private $exec_ctx = array(); private $color = false; private $indent_char = ' '; private $newline_char = "\n"; private $indent_level = 0; private $indent_width = 4; private $current_pos = 0; private $controls = array(); private $context_map = array(); private $context = false; private $new_line = "\n"; // private $file_lines = array(); // can be useful for debugging of problem with line numbers private $sniff_errors = array(/* error text => array(lines) */); private $white_space_map = array( "\r" => "", "\0" => "", ); private $constants = array( 'true' => 1, 'false' => 1, 'null' => 1, ); function __construct($filename, $fsm_rules, $controls) { $this->init(); $this->initFile($filename); $this->initControls($controls); $this->FSM = new PHPCodeFSM($fsm_rules); } private function initFile($filename) { if (!is_readable($filename)) { fwrite(STDERR, "ERROR: can't read file '" . $filename . "', will exit.\n"); exit(1); } $body = file_get_contents($filename); // $this->file_lines = file($filename); // can be useful for debugging of problem with line numbers $this->prepareTokens($body); } private function init() { $this->white_space_map += array( " " => $this->indent_char, "\t" => $this->indent_char, "\n" => $this->newline_char, ); $this->color = posix_isatty(1); } private function isDebug() { return PHPCF_DEBUG; } private function debug($m, $data = null) { if ($this->isDebug()) { echo $m, "\n"; if ($data !== null) { var_dump($data); } } } /* text inside HEREDOCs is tokenized in PHP by default, which is not what we need at all */ private function tokenHookHeredoc(&$tokens, $idx_tokens, $i_value) { $processed_tokens = array(); $heredoc_value = ''; $this->current_line = $i_value[2]; $processed_tokens[] = array( PHPCF_KEY_CODE => $idx_tokens[$i_value[0]], PHPCF_KEY_TEXT => $i_value[1], PHPCF_KEY_LINE => $this->current_line, ); while (list(, $i_value) = each($tokens)) { if ($i_value[0] === T_END_HEREDOC) { $this->current_line = $i_value[2]; $processed_tokens[] = array( PHPCF_KEY_CODE => 'T_HEREDOC_CONTENTS', PHPCF_KEY_TEXT => $heredoc_value, PHPCF_KEY_LINE => $this->current_line, ); break; } if (is_array($i_value)) { $heredoc_value .= $i_value[1]; $this->current_line = $i_value[2]; } else { $heredoc_value .= $i_value; } } $processed_tokens[] = array( PHPCF_KEY_CODE => $idx_tokens[$i_value[0]], PHPCF_KEY_TEXT => $i_value[1], PHPCF_KEY_LINE => $this->current_line, ); return $processed_tokens; } /* text inside "strings" is also tokenized in PHP by default: we do not care about these */ private function tokenHookDblStr(&$tokens) { $quote_token = array( PHPCF_KEY_CODE => '"', PHPCF_KEY_TEXT => '"', PHPCF_KEY_LINE => $this->current_line, ); $string_value = ''; $processed_tokens = array(); $processed_tokens[] = $quote_token; while (list(, $i_value) = each($tokens)) { if ($i_value === '"') { $processed_tokens[] = array( PHPCF_KEY_CODE => 'T_STRING_CONTENTS', PHPCF_KEY_TEXT => $string_value, PHPCF_KEY_LINE => $this->current_line, ); break; } if (is_array($i_value)) { $string_value .= $i_value[1]; $this->current_line = $i_value[2]; } else { $string_value .= $i_value; } } $quote_token[PHPCF_KEY_LINE] = $this->current_line; $processed_tokens[] = $quote_token; return $processed_tokens; } private function countExprLength(&$tokens, $found_first_bracket = false, $max_length) { $length = 0; $depth = $found_first_bracket ? 1 : 0; $current_pos = key($tokens); // not using next() as do not want to move array pointer for ($i = $current_pos; $i < count($tokens); $i++) { $token = $tokens[$i]; if (!$found_first_bracket) { if ($token == '(') $found_first_bracket = true; else continue; } // allow having long array definitions if user has decided that there should be an array in long form // also, functions are always required to be on separate lines, so we will consider having opening brace // as a sign that this expression is "long" if ($token === '{' || $token[0] === T_WHITESPACE && strpos($token[1], "\n") !== false) { return $max_length + 1; } if (is_array($token)) $length += strlen($token[1]); else $length += strlen($token); if ($length > $max_length) break; if ($token === '(') $depth++; if ($token === ')') $depth--; if ($depth <= 0) break; } return $length; } // T_ARRAY => T_ARRAY_LONG in case of array with a lot of contents private function tokenHookOpenBrace(&$tokens, $idx_tokens, $i_value) { $length = $this->countExprLength($tokens, true, PHPCF_LONG_EXPRESSION_LENGTH); $token = '('; if ($length >= PHPCF_LONG_EXPRESSION_LENGTH) $token = '(_LONG'; return array( array( PHPCF_KEY_CODE => $token, PHPCF_KEY_TEXT => '(', PHPCF_KEY_LINE => $this->current_line, ) ); } private function shouldIgnoreToken($token) { return $token == T_WHITESPACE || $token == T_COMMENT; } private function tokenHookCheckUnary(&$tokens, $idx_tokens, $i_value) { static $left_expression_symbols = array(']', ')', T_LNUMBER, T_DNUMBER, T_VARIABLE, T_STRING,); $is_unary = false; $current_pos = key($tokens) - 1; // token position is already pointing to next token // token is unary if there is no expression on the left for ($i = $current_pos - 1; $i > 0; $i--) { $tok = $tokens[$i]; if (is_array($tok) && $this->shouldIgnoreToken($tok[0])) continue; if (is_array($tok)) $tok = $tok[0]; if (!in_array($tok, $left_expression_symbols, true)) { $is_unary = true; } break; } $token = $i_value . ($is_unary ? '_UNARY' : ''); return array( array( PHPCF_KEY_CODE => $token, PHPCF_KEY_TEXT => $i_value, PHPCF_KEY_LINE => $this->current_line, ) ); } // interpret "static" in "static::HELLO" as normal text (T_STRING) instead of keyword (T_STATIC) private function tokenHookStatic(&$tokens, $idx_tokens, $i_value) { static $right_normal_context_symbols = array( T_VARIABLE, // static $var; protected static $var; T_PROTECTED, T_PUBLIC, T_PRIVATE, T_FINAL, T_VAR, T_ABSTRACT, // static protected $var; T_FUNCTION, // static function() { ... } ); $is_normal_context = false; $next_pos = key($tokens); $this->current_line = $i_value[2]; for ($i = $next_pos; $i < count($tokens); $i++) { $tok = $tokens[$i]; if (is_array($tok) && $this->shouldIgnoreToken($tok[0])) continue; if (in_array($tok[0], $right_normal_context_symbols, true)) $is_normal_context = true; break; } if ($is_normal_context) return $this->tokenHookClassdef($tokens, $idx_tokens, $i_value); return array( array( PHPCF_KEY_CODE => 'T_STRING', PHPCF_KEY_TEXT => 'static', PHPCF_KEY_LINE => $this->current_line, ) ); } // check for newline after "const", "private", etc and check if it is something like this: // const // CONST1 = "Something", // CONST2 = "Another thing"; private function tokenHookClassdef(&$tokens, $idx_tokens, $i_value) { $token = $idx_tokens[$i_value[0]]; $this->current_line = $i_value[2]; $next_pos = key($tokens); $is_property_def = false; $is_newline = false; // whether or not definition is on a new line for ($i = $next_pos; $i < count($tokens); $i++) { $tok = $tokens[$i]; // look for whitespace, comment, variable or constant name after, e.g. "private" // if nothing was found, then it is end of property def (or real property def did not begin) if ($tok[0] === T_VARIABLE || $tok[0] === T_STRING) $is_property_def = true; else if ($tok[0] !== T_COMMENT && $tok[0] != T_WHITESPACE) break; if (strpos($tok[1], "\n") !== false) $is_newline = true; } if ($is_property_def && $is_newline) $token .= '_NL'; return array( array( PHPCF_KEY_CODE => $token, PHPCF_KEY_TEXT => $i_value[1], PHPCF_KEY_LINE => $this->current_line, ) ); } private function appendWhiteSpace(&$tokens, &$return_tokens, $text = "\n") { $next_token = current($tokens); if ($next_token[0] !== T_WHITESPACE) { $return_tokens[] = array( PHPCF_KEY_CODE => 'T_WHITESPACE', PHPCF_KEY_TEXT => $text, PHPCF_KEY_LINE => $this->current_line, ); } else { $tokens[key($tokens)][1] = "\n" . $tokens[key($tokens)][1]; } } // only long "<?php" open tags are allowed by our rules private function tokenHookOpenTag(&$tokens, $idx_tokens, $i_value) { $open_tag = "<?php"; $this->current_line = $i_value[2]; if (rtrim($i_value[1]) !== $open_tag) $this->sniffMessage('Only "<?php" allowed as open tag'); $ret = array( array( PHPCF_KEY_CODE => 'T_OPEN_TAG', PHPCF_KEY_TEXT => $open_tag, PHPCF_KEY_LINE => $this->current_line, ) ); $this->appendWhiteSpace($tokens, $ret); return $ret; } // T_INC => T_INC_LEFT || T_INC_RIGHT ( T_INC_LEFT in case "++$a", T_INC_RIGHT in case "$a++") private function tokenHookIncrement(&$tokens, $idx_tokens, $i_value) { $next_pos = key($tokens); $is_left = false; if ($next_pos) { for ($i = $next_pos; $i < count($tokens); $i++) { $tok = $tokens[$i]; if (is_array($tok) && $this->shouldIgnoreToken($tok[0])) continue; // in situations like '++ $a' there would be variable on the right, so the token is positioned left if ($tok[0] === T_VARIABLE) $is_left = true; break; } } $token = $idx_tokens[$i_value[0]] . ($is_left ? '_LEFT' : '_RIGHT'); $this->current_line = $i_value[2]; return array( array( PHPCF_KEY_CODE => $token, PHPCF_KEY_TEXT => $i_value[1], PHPCF_KEY_LINE => $this->current_line, ) ); } private function isLineAligned($line_pos, $line_length, $whitespace_length, &$tokens) { $other_line_length = 0; for ($i = $line_pos; $i < count($tokens); $i++) { $tok = $tokens[$i]; if (!is_array($tok)) { $other_line_length += strlen($tok); } else { $is_str = $tok[0] === T_CONSTANT_ENCAPSED_STRING || $tok[0] === T_ENCAPSED_AND_WHITESPACE; if (!$is_str && strpos($tok[1], "\n") !== false) break; $other_line_length += strlen($tok[1]); } if ($other_line_length == $whitespace_length && $tok[0] === T_WHITESPACE) { // aligned by whitespace return true; } else if ($other_line_length == $line_length && $tokens[$i - 1][0] === T_WHITESPACE) { // aligned by tokens! return true; } else if ($other_line_length > $line_length) { // no chance break; } } return false; } private function isPrevLineAligned($prev_line_pos, $line_length, $whitespace_length, &$tokens) { for ($i = $prev_line_pos; $i >= 0; $i--) { // find beginning of line $tok = $tokens[$i]; if (!is_array($tok)) continue; $is_str = $tok[0] === T_CONSTANT_ENCAPSED_STRING || $tok[0] === T_ENCAPSED_AND_WHITESPACE; if (!$is_str && strpos($tok[1], "\n") !== false) break; } if ($i < $prev_line_pos) { return $this->isLineAligned($i + 1, $line_length, $whitespace_length, $tokens); } return false; } private function isNextLineAligned($next_line_pos, $line_length, $whitespace_length, &$tokens) { for ($i = $next_line_pos; $i < count($tokens); $i++) { // find beginning of line $tok = $tokens[$i]; if (!is_array($tok)) continue; $is_str = $tok[0] === T_CONSTANT_ENCAPSED_STRING || $tok[0] === T_ENCAPSED_AND_WHITESPACE; if (!$is_str && strpos($tok[1], "\n") !== false) break; } if ($i > $next_line_pos) { return $this->isLineAligned($i + 1, $line_length, $whitespace_length, $tokens); } return false; } // find aligned expressions private function tokensIsWhiteSpaceAligned(&$tokens, $i_value) { $next_pos = key($tokens); // either it's EOF or whitespace has tabs/newlines or it has length less than 2 if (!$next_pos || !preg_match('/^ +$/s', $i_value[1])) { return false; } // search for beginning of line and count length of line before this whitespace $whitespace_length = $line_length = 0; for ($i = $next_pos; $i >= 0; $i--) { $tok = $tokens[$i]; if (!is_array($tok)) { $line_length += strlen($tok); if ($i != $next_pos) $whitespace_length += strlen($tok); } else { $is_str = $tok[0] === T_CONSTANT_ENCAPSED_STRING || $tok[0] === T_ENCAPSED_AND_WHITESPACE; if (!$is_str && strpos($tok[1], "\n") !== false) break; // this will skip the indent as well, we do not care $line_length += strlen($tok[1]); if ($i != $next_pos) $whitespace_length += strlen($tok[1]); } } $is_aligned = false; if ($i > 0) $is_aligned = $this->isPrevLineAligned($i - 1, $line_length, $whitespace_length, $tokens); if (!$is_aligned) $is_aligned = $this->isNextLineAligned($next_pos, $line_length, $whitespace_length, $tokens); return $is_aligned; } private function tokenHookWhiteSpace(&$tokens, $idx_tokens, $i_value) { // fix for bug with wrong line numbers of tokens like "{" which do not have line number assotiated with them $this->current_line = $i_value[2] + substr_count($i_value[1], "\n"); if ($this->tokensIsWhiteSpaceAligned($tokens, $i_value)) $token = 'T_WHITESPACE_ALIGNED'; else $token = 'T_WHITESPACE'; return array( array( PHPCF_KEY_CODE => $token, PHPCF_KEY_TEXT => $i_value[1], PHPCF_KEY_LINE => $this->current_line, ) ); } private function tokenHookElse(&$tokens, $idx_tokens, $i_value) { $token = $idx_tokens[$i_value[0]]; $this->current_line = $i_value[2]; $next_pos = key($tokens); $has_block_before = false; for ($i = $next_pos - 2; $i > 0; $i--) { $tok = $tokens[$i]; if (is_array($tok) && $this->shouldIgnoreToken($tok[0])) continue; if ($tok === '}') $has_block_before = true; break; } if (!$has_block_before) $token .= '_INLINE'; return array( array( PHPCF_KEY_CODE => $token, PHPCF_KEY_TEXT => $i_value[1], PHPCF_KEY_LINE => $this->current_line, ) ); } // "// comment\n" is split into 2 tokens "// comment" and "\n", and "\n" is prepended to previous whitespace token // if present. This split allows not to take easy cases with single-line comments into account private function tokenHookComment(&$tokens, $idx_tokens, $i_value) { $token = $idx_tokens[$i_value[0]]; $this->current_line = $i_value[2]; if (substr($i_value[1], 0, 2) == '//' || $i_value[1][0] == '#') { // if previous token is whitespace with line feed, then it means that this comment takes whole line $prev_pos = key($tokens) - 2; // otherwise it is appended to some expression like this one if ($prev_pos > 1 && $tokens[$prev_pos][0] === T_WHITESPACE && strpos($tokens[$prev_pos][1], "\n") !== false) { $token = 'T_SINGLE_LINE_COMMENT_ALONE'; } else { $token = 'T_SINGLE_LINE_COMMENT'; } $i_value[1] = rtrim($i_value[1]); } $ret = array( array( PHPCF_KEY_CODE => $token, PHPCF_KEY_TEXT => $i_value[1], PHPCF_KEY_LINE => $this->current_line, ), ); if ($token == 'T_COMMENT') return $ret; $this->appendWhiteSpace($tokens, $ret); return $ret; } private function tokenHookConcat(&$tokens, $idx_tokens, $i_value) { $next_pos = key($tokens); $prev_pos = key($tokens) - 2; $token = '.'; if ($tokens[$next_pos][0] === T_WHITESPACE && strpos($tokens[$next_pos][1], "\n") !== false) { $token = '._NL'; } else if ($tokens[$prev_pos][0] === T_WHITESPACE && strpos($tokens[$prev_pos][1], "\n") !== false) { $token = '._NL'; } return array( array( PHPCF_KEY_CODE => $token, PHPCF_KEY_TEXT => '.', PHPCF_KEY_LINE => $this->current_line, ), ); } private function tokenHookConstant(&$tokens, $idx_tokens, $i_value) { $this->current_line = $i_value[2]; $value = strtolower($i_value[1]); if (!isset($this->constants[$value])) { $value = $i_value[1]; } else if ($value != $i_value[1]) { $this->sniffMessage('Reserved word "' . $value . '" must be written in lowercase'); } return array( array( PHPCF_KEY_CODE => $idx_tokens[$i_value[0]], PHPCF_KEY_TEXT => $value, PHPCF_KEY_LINE => $this->current_line, ) ); } private function isLongComma(&$tokens, $max_length, $remember_positions = false) { static $last_long_position = -1; $curr_pos = key($tokens) - 1; $len = 0; $depth = 0; // getting first right non-whitespace token length (only if it is not ) for ($i = $curr_pos + 1; $i < count($tokens); $i++) { $tok = $tokens[$i]; if (is_array($tok)) { if ($tok[0] === T_WHITESPACE) { if (strpos($tok[0], "\n") !== false) break; continue; } $len += strlen($tok[1]); } else { if ($tok == ')') break; $len += strlen($tok); } break; } // going backwards to see if there already is more than 120 symbols in line for ($i = $curr_pos; $i > 0; $i--) { // we can remember that which comma was long and // count the next long comma only starting from the previous long one if ($i == $last_long_position) break; $tok = $tokens[$i]; // we should stop when line beginning is reached or in another special case described below if (is_array($tok)) { if (strpos($tok[0], "\n") !== false) break; if ($tok[0] === T_WHITESPACE) continue; $len += strlen($tok[1]); } else { if ($tok == ',') $len += 2; else if ($tok == '(') $depth--; else if ($tok == ')') $depth++; else $len += strlen($tok); } // found opening "(" before reaching max length, which means it is something like this: // array( 'something', some_func($argument100, $argument200), 'something else' ) // ^ our brace ^ our comma // such comma must not be long even though the length before newline can be higher than max. // comma must be directly related to the array (or argument list), but in this case it does not if ($depth < 0) return false; if ($depth == 0 && $len >= $max_length) break; } $is_long = $len >= $max_length; if ($remember_positions && $is_long) $last_long_position = $curr_pos; return $is_long; } private function tokenHookComma(&$tokens, $idx_tokens, $i_value) { $token = ','; if ($this->isLongComma($tokens, PHPCF_LONG_EXPRESSION_LENGTH, true)) $token .= '_LONG'; return array( array( PHPCF_KEY_CODE => $token, PHPCF_KEY_TEXT => ',', PHPCF_KEY_LINE => $this->current_line, ) ); } private $token_hook_names = array( // hook should return all parsed tokens T_START_HEREDOC => 'tokenHookHeredoc', '.' => 'tokenHookConcat', '"' => 'tokenHookDblStr', '(' => 'tokenHookOpenBrace', '+' => 'tokenHookCheckUnary', '-' => 'tokenHookCheckUnary', '&' => 'tokenHookCheckUnary', ',' => 'tokenHookComma', T_STATIC => 'tokenHookStatic', T_OPEN_TAG => 'tokenHookOpenTag', T_INC => 'tokenHookIncrement', T_DEC => 'tokenHookIncrement', T_WHITESPACE => 'tokenHookWhiteSpace', T_ELSE => 'tokenHookElse', T_ELSEIF => 'tokenHookElse', T_COMMENT => 'tokenHookComment', T_STRING => 'tokenHookConstant', T_VAR => 'tokenHookClassdef', T_PUBLIC => 'tokenHookClassdef', T_PROTECTED => 'tokenHookClassdef', T_PRIVATE => 'tokenHookClassdef', T_CONST => 'tokenHookClassdef', T_FINAL => 'tokenHookClassdef', ); private function prepareTokens($body) { $tokens = token_get_all($body); $list_tokens = preg_grep('/^T_/', array_keys(get_defined_constants())); $idx_tokens = array(); foreach ($list_tokens as $i_token) { $idx_tokens[constant($i_token)] = $i_token; } $this->tokens = array(); $in_nowdoc = $in_heredoc = $in_string = false; $heredoc_value = $string_value = ''; // iterate array manually so that we can read several tokens in hooks and auto-advance position reset($tokens); while (list(, $i_value) = each($tokens)) { $tok = is_array($i_value) ? $i_value[0] : $i_value; if (isset($this->token_hook_names[$tok])) { $method_name = $this->token_hook_names[$tok]; $result = $this->$method_name($tokens, $idx_tokens, $i_value); foreach ($result as $parsed_token) { $this->tokens[] = $parsed_token; } continue; } if (is_array($i_value)) { $this->current_line = $i_value[2]; $this->tokens[] = array( PHPCF_KEY_CODE => $idx_tokens[$i_value[0]], PHPCF_KEY_TEXT => $i_value[1], PHPCF_KEY_LINE => $this->current_line, ); $this->current_line += substr_count($i_value[1], "\n"); } else { $this->tokens[] = array( PHPCF_KEY_CODE => $i_value, PHPCF_KEY_TEXT => $i_value, PHPCF_KEY_LINE => $this->current_line, ); } } } public function dumpStruct() { echo str_repeat("=", 100) . "\n"; $i = 0; ob_start(); foreach ($this->tokens as $i_data) { printf("%5d: ", $i); echo $i_data[PHPCF_KEY_CODE] . " " . $this->humanWhiteSpace($i_data[PHPCF_KEY_TEXT], true); if (isset($i_data[PHPCF_KEY_TOKEN_LENGTH])) { echo " " . $i_data[PHPCF_KEY_TOKEN_LENGTH]; } echo "\n"; $i++; } ob_end_flush(); } public function dump() { echo str_repeat("=", 100) . "\n"; $i = 0; $n_exec = count($this->exec); while ($i < $n_exec) { $i_exec = $this->exec[$i]; if (is_string($i_exec)) { echo sprintf("%5d", $i) . ': ' . $this->humanWhiteSpace($i_exec, true) . "\n"; $i++; } else { $list_exec = array(); while (!is_string($i_exec)) { if (is_array($i_exec)) { foreach ($i_exec as $i_byte) { $list_exec[] = $this->getHumanReadableExecByte($i_byte); } } else { $list_exec[] = $this->getHumanReadableExecByte($i_exec); } $i++; $i_exec = $this->exec[$i]; } echo sprintf("%5d", $i) . ': PHPCF_EXEC = {' . implode(', ', $list_exec) . "}\n"; } } } private function getHumanReadableExecByte($byte) { static $map = array( PHPCF_EX_DELETE_SPACES => 'PHPCF_EX_DELETE_SPACES', PHPCF_EX_DELETE_SPACES_STRONG => 'PHPCF_EX_DELETE_SPACES_STRONG', PHPCF_EX_SHRINK_SPACES => 'PHPCF_EX_SHRINK_SPACES', PHPCF_EX_SHRINK_SPACES_STRONG => 'PHPCF_EX_SHRINK_SPACES_STRONG', PHPCF_EX_SHRINK_NLS => 'PHPCF_EX_SHRINK_NLS', PHPCF_EX_SHRINK_NLS_STRONG => 'PHPCF_EX_SHRINK_NLS_STRONG', PHPCF_EX_SHRINK_NLS_2 => 'PHPCF_EX_SHRINK_NLS_2', PHPCF_EX_CHECK_NL => 'PHPCF_EX_CHECK_NL', PHPCF_EX_CHECK_NL_STRONG => 'PHPCF_EX_CHECK_NL_STRONG', PHPCF_EX_INCREASE_INDENT => 'PHPCF_EX_INCREASE_INDENT', PHPCF_EX_DECREASE_INDENT => 'PHPCF_EX_DECREASE_INDENT', PHPCF_EX_NL_OR_SPACE => 'PHPCF_EX_NL_OR_SPACE', PHPCF_EX_DO_NOT_TOUCH_ANYTHING => 'PHPCF_EX_DO_NOT_TOUCH_ANYTHING' ); if (empty($map[$byte])) return 'UNKNOWN - "' . $byte . '"'; return $map[$byte]; } private function getHumanReadableExecSequence($sequence) { $parts = array(); foreach ($sequence as $v) { if (is_int($v)) $parts[] = $this->getHumanReadableExecByte($v); else $parts[] = $this->humanWhiteSpace($v); } return implode(', ', $parts); } public function sanitizeWhiteSpace($s) { return strtr($s, $this->white_space_map); } public function exec($lines = null) { if ($this->isDebug()) { $this->dumpStruct(); $this->dump(); echo str_repeat("=", 100) . "\n"; } if (!count($this->exec)) return ''; // empty file $exec_ctx = array(); $exec_sequence = array(); $out = ''; foreach ($this->exec as $i => $i_exec) { $ctx = $this->exec_ctx[$i]; $line = $this->tokens[$ctx['current_pos']][PHPCF_KEY_LINE]; if (is_string($i_exec)) { if ($ctx['whitespace']) { if (!isset($lines) || isset($lines[$line])) { $exec_sequence[] = $this->sanitizeWhiteSpace($i_exec); } else { $exec_sequence[] = $i_exec; } $exec_ctx[] = $ctx; } else { if (!empty($exec_sequence)) { $out .= $this->execSequence($exec_sequence, $exec_ctx, $line, $lines); $exec_sequence = array(); $exec_ctx = array(); } $out .= $i_exec; } } elseif (is_array($i_exec)) { foreach ($i_exec as $i) { $exec_sequence[] = $i; $exec_ctx[] = $ctx; } } else { $exec_sequence[] = $i_exec; $exec_ctx[] = $ctx; } } if (!empty($exec_sequence)) { $out .= $this->execSequence($exec_sequence, $exec_ctx, $line, $lines); } return $out; } static $exec_methods = array( PHPCF_EX_CHECK_NL_STRONG => 'execCheckNewline', PHPCF_EX_CHECK_NL => 'execCheckNewline', PHPCF_EX_DELETE_SPACES_STRONG => 'execDeleteSpaces', PHPCF_EX_DELETE_SPACES => 'execDeleteSpaces', PHPCF_EX_SHRINK_SPACES => 'execShrinkSpaces', PHPCF_EX_SHRINK_SPACES_STRONG => 'execShrinkSpaces', PHPCF_EX_SHRINK_NLS_2 => 'execShrinkNewlines2', PHPCF_EX_SHRINK_NLS => 'execShrinkNewlines', PHPCF_EX_SHRINK_NLS_STRONG => 'execShrinkNewlines', PHPCF_EX_NL_OR_SPACE => 'execNewlineOrSpace', PHPCF_EX_DO_NOT_TOUCH_ANYTHING => 'execNothing', ); private function execCheckNewline($in) { if (substr_count($in, "\n") >= 2) return "\n\n"; // allow 2 new lines return "\n"; } private function execDeleteSpaces($in) { return ''; } private function execShrinkSpaces($in) { return ' '; } private function execShrinkNewlines($in) { return "\n"; } private function execShrinkNewlines2($in) { return "\n\n"; } private function execNewlineOrSpace($in) { if (strpos($in, "\n") !== false) return "\n"; return ' '; } private function execNothing($in) { return $in; } private function execSequence($sequence, $exec_ctx, $line, $lines) { $c = array(); $in = ''; $out = ''; $context = array( 'descr' => 'correct indentation level', 'current_pos' => $exec_ctx[0] ? $exec_ctx[0]['current_pos'] : null, ); for ($i = 0; $i < count($sequence); $i++) { if (is_int($sequence[$i])) { if (PHPCF_EX_INCREASE_INDENT == $sequence[$i]) { $this->indent_level++; } elseif (PHPCF_EX_DECREASE_INDENT == $sequence[$i]) { if ($this->indent_level > 0) { $this->indent_level--; } } else { $c[$sequence[$i]] = $exec_ctx[$i] ? $exec_ctx[$i] : 1; } } else { $in .= $sequence[$i]; } } // account for ignoring lines if (isset($lines) && !isset($lines[$line])) return $in; if (count($c)) { // the executors with less value have higher precedence $min_key = min(array_keys($c)); $action = self::$exec_methods[$min_key]; $out = $this->$action($in); $context = $c[$min_key]; } else { $out = $in; } if (false !== strpos($out, "\n")) { $out = rtrim($out, ' '); $out .= $this->getIndentString(); } if ($in !== $out) { $this->sniff($in, $out, $context, $sequence); } return $out; } function humanWhiteSpace($str, $color = false) { static $whitespace_map, $colored_whitespace_map; if (!isset($whitespace_map)) { $whitespace_map = array("\n" => '\n', "\r" => '\r', "\t" => '\t', " " => ' '); $colored_whitespace_map = array("\n" => '\n', "\r" => '\r', "\t" => '\t', " " => 'ยท'); foreach ($colored_whitespace_map as &$v) { $v = "\033[38;5;246m" . $v . "\033[0m"; } unset($v); } return strtr($str, $this->color && $color ? $colored_whitespace_map : $whitespace_map); } private function msg($message) { fwrite(STDERR, $message . "\n"); } private function sniffMessage($message) { if (!PHPCF_SNIFF) return; $this->sniff_exit_code = 1; $this->sniff_errors[$message][] = $this->current_line; // $this->msg(sprintf("line%6d) %s\n\n", $this->current_line, $message)); } private function sniff($in, $out, $context, $sequence) { if (!PHPCF_SNIFF) return; $this->sniff_exit_code = 1; $current_pos = $context['current_pos']; $this->sniff_errors[$context['descr']][] = $this->tokens[$current_pos][PHPCF_KEY_LINE]; } function printSnifferMessages($lines_opt) { if (!PHPCF_SNIFF || !count($this->sniff_errors)) return; if (PHPCF_SUMMARY) { if ($this->sniff_errors) { $this->msg('Total errors: ' . array_sum(array_map('count', $this->sniff_errors))); } } else { if (count($this->sniff_errors) && isset($lines_opt)) { $this->msg(' Checking with --lines=' . $lines_opt . "\n"); } foreach ($this->sniff_errors as $text => $lines) { $lines = array_unique($lines); $text = ' Expecting ' . lcfirst($text); $wrapped_lines = wordwrap(implode(' ', $lines), 70, "\n "); $msg = sprintf("%s:\n line%s %s\n", $text, count($lines) > 1 ? 's' : '', $wrapped_lines); $this->msg($msg); } } } private function next() { if ($this->current_pos + 1 >= count($this->tokens)) { return false; } $this->current_pos++; $this->setContext(); return $this->tokens[$this->current_pos]; } private function setContext() { // $this->debug("==== FSM->setContext called for " . $this->getCode()); $this->FSM->transit($this->tokens[$this->current_pos][PHPCF_KEY_CODE]); $this->context = $this->FSM->getState(); // $this->debug("==== FSM->setContext sets new context to " . $this->context); } private function initControls($controls) { $this->controls = array(); foreach ($controls as $key => $data) { $list_keys = explode(' ', $key); if (empty($list_keys)) { $list_keys = array($key); } foreach ($list_keys as $i_key) { foreach ($data as $j_key => $j_data) { $j_list_keys = explode(' ', $j_key); if (empty($j_list_keys)) { $j_list_keys = array($j_key); } foreach ($j_list_keys as $k) { $this->controls[$i_key][$k] = $j_data; } } } } } private function getContext() { $rules = $this->FSM->current_rules; return array( 'current_pos' => $this->current_pos, 'whitespace' => $this->tokens[$this->current_pos][PHPCF_KEY_CODE] === 'T_WHITESPACE', ); } public function process() { if (!$this->tokens) return; // empty file $this->setContext(); do { $cur_token = $this->tokens[$this->current_pos]; $i_code = $cur_token[PHPCF_KEY_CODE]; $i_text = $cur_token[PHPCF_KEY_TEXT]; if ($this->isDebug()) { $debug_code = sprintf("%30s", $i_code); $whitespaces = str_repeat(' ', max(0, 30 - strlen($i_text))); $msg = $debug_code . " " . $this->humanWhiteSpace($i_text, true) . $whitespaces; $msg .= " " . $this->FSM->getStackPath(); $this->debug($msg); } $rule_context = $this->getContext(); if (empty($this->controls[$i_code])) { $this->exec[] = $i_text; $this->exec_ctx[] = $rule_context; continue; } $i_controls = $this->controls[$i_code]; $i_context_controls = false; if (!empty($i_controls[$this->context])) { $i_context_controls = $i_controls[$this->context]; } elseif (!empty($i_controls[PHPCF_KEY_ALL])) { $i_context_controls = $i_controls[PHPCF_KEY_ALL]; } if (!empty($i_context_controls)) { $this->processControls($i_context_controls, $rule_context); } else { $this->exec[] = $i_text; $this->exec_ctx[] = $rule_context; } } while ($this->next()); } private function isWhiteSpaceAligned($pos) { if (!isset($this->tokens[$pos][PHPCF_KEY_CODE])) return false; return $this->tokens[$pos][PHPCF_KEY_CODE] == 'T_WHITESPACE_ALIGNED'; } function processControls($controls, $context) { $i = count($this->exec); if (!empty($controls[PHPCF_KEY_LEFT]) && !$this->isWhiteSpaceAligned($this->current_pos - 1)) { $c = $controls[PHPCF_KEY_LEFT]; $this->exec_ctx[$i] = $context + array('descr' => $controls[PHPCF_KEY_DESCR_LEFT], 'from' => PHPCF_KEY_LEFT); if (is_array($c)) { $this->exec[$i] = array(); foreach ($c as $i_c) $this->exec[$i][] = $i_c; } else { $this->exec[$i] = array($c); } $i++; } $this->exec_ctx[$i] = $context; $this->exec[$i] = $this->tokens[$this->current_pos][PHPCF_KEY_TEXT]; if (!empty($controls[PHPCF_KEY_RIGHT]) && !$this->isWhiteSpaceAligned($this->current_pos + 1)) { $i++; $c = $controls[PHPCF_KEY_RIGHT]; $this->exec_ctx[$i] = $context + array('descr' => $controls[PHPCF_KEY_DESCR_RIGHT], 'from' => PHPCF_KEY_RIGHT); if (is_array($c)) { $this->exec[$i] = array(); foreach ($c as $i_c) $this->exec[$i][] = $i_c; } else { $this->exec[$i] = $c; } } } function getIndentString() { return str_repeat($this->indent_char, $this->indent_level * $this->indent_width); } } $casts = 'T_INT_CAST T_DOUBLE_CAST T_BOOL_CAST T_STRING_CAST T_ARRAY_CAST T_OBJECT_CAST T_UNSET_CAST'; $controls = array( '{' => array( 'CTX_INLINE_BRACE' => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before "{" in "->{...}" expression', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES, PHPCF_KEY_DESCR_RIGHT => 'No whitespace after "{" in "->{...}" expression', PHPCF_KEY_RIGHT => PHPCF_EX_DELETE_SPACES, ), 'CTX_FUNCTION_D CTX_CLASS_D CTX_CLASS_METHOD_D' => array( PHPCF_KEY_DESCR_LEFT => 'New line before "{" in function/method/class declaration', PHPCF_KEY_LEFT => PHPCF_EX_SHRINK_NLS, PHPCF_KEY_DESCR_RIGHT => 'Indent and 1 or 2 newlines with proper indent after "{"', PHPCF_KEY_RIGHT => array(PHPCF_EX_INCREASE_INDENT, PHPCF_EX_SHRINK_NLS), ), PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_LEFT => 'One space before "{"', PHPCF_KEY_LEFT => PHPCF_EX_SHRINK_SPACES_STRONG, PHPCF_KEY_DESCR_RIGHT => 'Indent and 1 or 2 newlines with proper indent after "{"', PHPCF_KEY_RIGHT => array(PHPCF_EX_INCREASE_INDENT, PHPCF_EX_SHRINK_NLS), ), ), '}' => array( 'CTX_INLINE_BRACE' => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before "}" in "->{...}" expression', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES, PHPCF_KEY_DESCR_RIGHT => 'No whitespace after "}" in "->{...}" expression', PHPCF_KEY_RIGHT => PHPCF_EX_DELETE_SPACES, ), 'CTX_CASE_END_OF_BLOCK' => array( PHPCF_KEY_DESCR_LEFT => 'Unindent and 1 or 2 newlines with proper indent after "}"', PHPCF_KEY_LEFT => array(PHPCF_EX_DECREASE_INDENT, PHPCF_EX_DECREASE_INDENT, PHPCF_EX_SHRINK_NLS), PHPCF_KEY_DESCR_RIGHT => '1 or 2 newlines with proper indent after "}"', PHPCF_KEY_RIGHT => PHPCF_EX_CHECK_NL, ), PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_LEFT => 'Unindent and 1 or 2 newlines with proper indent after "}"', PHPCF_KEY_LEFT => array(PHPCF_EX_DECREASE_INDENT, PHPCF_EX_SHRINK_NLS), PHPCF_KEY_DESCR_RIGHT => '1 or 2 newlines with proper indent after "}"', PHPCF_KEY_RIGHT => PHPCF_EX_CHECK_NL, ), ), 'T_IF T_FOR T_FOREACH T_DO T_ELSE_INLINE T_ELSEIF_INLINE T_TRY' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_LEFT => '1 or 2 newlines with proper indent before control statements', PHPCF_KEY_LEFT => PHPCF_EX_CHECK_NL, PHPCF_KEY_DESCR_RIGHT => 'One space after control statements', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES_STRONG, ), ), 'T_AS T_ELSEIF T_ELSE T_CATCH' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_LEFT => 'One space before as, elseif, else, catch', PHPCF_KEY_LEFT => PHPCF_EX_SHRINK_SPACES_STRONG, PHPCF_KEY_DESCR_RIGHT => 'One space after as, elseif, else, catch', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES_STRONG, ) ), 'T_WHILE' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_LEFT => '1 or 2 newlines with proper indent before "while"', PHPCF_KEY_LEFT => PHPCF_EX_CHECK_NL, PHPCF_KEY_DESCR_RIGHT => 'One space after "while"', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES_STRONG, ), 'CTX_WHILE_AFTER_DO' => array( PHPCF_KEY_DESCR_LEFT => '1 or 2 newlines with proper indent before "while" in "do/while"', PHPCF_KEY_LEFT => PHPCF_EX_SHRINK_SPACES_STRONG, PHPCF_KEY_DESCR_RIGHT => 'One space after "while" in "do/while"', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES_STRONG, ), ), 'T_CLASS T_INTERFACE' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_LEFT => '2 newlines with proper indent before "class/interface"', PHPCF_KEY_LEFT => PHPCF_EX_SHRINK_NLS_2, PHPCF_KEY_DESCR_RIGHT => 'One space after class/interface name', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES, ), ), 'T_EXTENDS T_IMPLEMENTS' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_LEFT => 'One space before "extends/implements"', PHPCF_KEY_LEFT => PHPCF_EX_SHRINK_SPACES, PHPCF_KEY_DESCR_RIGHT => 'One space after "extends/implements"', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES, ) ), 'T_STATIC T_VAR T_PUBLIC T_PRIVATE T_PROTECTED T_CONST T_FINAL T_ABSTRACT' => array( 'CTX_CLASS' => array( PHPCF_KEY_DESCR_LEFT => '1 or 2 newlines with proper indent before class properties/methods declarations', PHPCF_KEY_LEFT => PHPCF_EX_CHECK_NL, PHPCF_KEY_DESCR_RIGHT => 'One space after "final", "abstract", "public" etc.', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES_STRONG, ), PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_RIGHT => 'One space after "final", "abstract", "public" etc.', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES_STRONG, ), ), 'T_STATIC_NL T_VAR_NL T_PUBLIC_NL T_PRIVATE_NL T_PROTECTED_NL T_CONST_NL T_FINAL_NL T_ABSTRACT_NL' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_RIGHT => 'New line and indent after end of property declaration', PHPCF_KEY_RIGHT => array(PHPCF_EX_INCREASE_INDENT, PHPCF_EX_SHRINK_NLS), ), ), 'T_OBJECT_OPERATOR T_DOUBLE_COLON' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before "::" and "->"', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES, PHPCF_KEY_DESCR_RIGHT => 'No whitespace after "::" and "->"', PHPCF_KEY_RIGHT => PHPCF_EX_DELETE_SPACES, ), ), '( (_LONG' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before "("', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES, PHPCF_KEY_DESCR_RIGHT => 'No whitespace after "("', PHPCF_KEY_RIGHT => PHPCF_EX_DELETE_SPACES, ), 'CTX_GENERIC_PARENTHESIS' => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before "("', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES, PHPCF_KEY_DESCR_RIGHT => 'No whitespace after "("', PHPCF_KEY_RIGHT => PHPCF_EX_DELETE_SPACES, ), 'CTX_LONG_PARENTHESIS CTX_ARRAY_LONG_PARENTHESIS' => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before "("', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES, PHPCF_KEY_DESCR_RIGHT => 'Newline after "(" in long expression', PHPCF_KEY_RIGHT => array(PHPCF_EX_INCREASE_INDENT, PHPCF_EX_CHECK_NL) ), ), ')' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before ")"', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES_STRONG, PHPCF_KEY_DESCR_RIGHT => 'One space after ")"', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES, ), 'CTX_GENERIC_PARENTHESIS' => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before ")"', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES_STRONG, PHPCF_KEY_DESCR_RIGHT => 'One space after ")"', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES, ), 'CTX_LONG_PAR_END' => array( PHPCF_KEY_DESCR_LEFT => 'Unindent and newline before ")" in long expression', PHPCF_KEY_LEFT => array(PHPCF_EX_DECREASE_INDENT, PHPCF_EX_CHECK_NL), PHPCF_KEY_DESCR_RIGHT => 'No whitespace after ")" in long expression', PHPCF_KEY_RIGHT => PHPCF_EX_DELETE_SPACES, ), 'CTX_INLINE_EXPR_NL_END' => array( PHPCF_KEY_DESCR_LEFT => 'Unindent and no whitespace before ")" in end of long expression', PHPCF_KEY_LEFT => array(PHPCF_EX_DECREASE_INDENT, PHPCF_EX_DELETE_SPACES_STRONG), PHPCF_KEY_DESCR_RIGHT => 'No whitespace after ")" in long expression', PHPCF_KEY_RIGHT => PHPCF_EX_DELETE_SPACES, ), 'CTX_LONG_EXPR_NL_END' => array( PHPCF_KEY_DESCR_LEFT => 'Unindent and newline before ")" in long expression', PHPCF_KEY_LEFT => array(PHPCF_EX_DECREASE_INDENT, PHPCF_EX_DECREASE_INDENT, PHPCF_EX_CHECK_NL), PHPCF_KEY_DESCR_RIGHT => 'No whitespace after ")" in long expression', PHPCF_KEY_RIGHT => PHPCF_EX_DELETE_SPACES, ) ), ';' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before ";"', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES_STRONG, PHPCF_KEY_DESCR_RIGHT => '1 or 2 newlines with proper indent after ";"', PHPCF_KEY_RIGHT => PHPCF_EX_CHECK_NL, ), 'CTX_FOR_PARENTHESIS' => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before ";"', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES_STRONG, PHPCF_KEY_DESCR_RIGHT => 'One space after ";" in for()', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES, ), 'CTX_INLINE_EXPR_NL_END' => array( PHPCF_KEY_DESCR_LEFT => 'Unindent and no whitespace before ")" in end of long expression', PHPCF_KEY_LEFT => array(PHPCF_EX_DECREASE_INDENT, PHPCF_EX_DELETE_SPACES_STRONG), PHPCF_KEY_DESCR_RIGHT => '1 or 2 newlines with proper indent after ";"', PHPCF_KEY_RIGHT => PHPCF_EX_CHECK_NL, ), 'CTX_CLASS_CONST_NL_END CTX_CLASS_VARIABLE_D_NL_END' => array( PHPCF_KEY_DESCR_LEFT => 'Unindent and no whitespace before ";" in end of long property definition', PHPCF_KEY_LEFT => array(PHPCF_EX_DECREASE_INDENT, PHPCF_EX_DELETE_SPACES_STRONG), PHPCF_KEY_DESCR_RIGHT => '1 or 2 newlines with proper indent after ";"', PHPCF_KEY_RIGHT => PHPCF_EX_CHECK_NL, ), ), 'T_AND_EQUAL T_CONCAT_EQUAL T_DIV_EQUAL T_IS_EQUAL T_IS_GREATER_OR_EQUAL ' . 'T_IS_NOT_EQUAL T_IS_SMALLER_OR_EQUAL T_MINUS_EQUAL T_MOD_EQUAL T_MUL_EQUAL ' . 'T_OR_EQUAL T_PLUS_EQUAL T_SL_EQUAL T_SR_EQUAL T_XOR_EQUAL ' . '= + & - * ^ % / ? | < > . T_IS_IDENTICAL T_IS_NOT_IDENTICAL T_IS_EQUAL T_IS_NOT_EQUAL ' . 'T_LOGICAL_AND T_BOOLEAN_AND T_LOGICAL_OR T_BOOLEAN_OR T_LOGICAL_XOR' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_LEFT => 'One space before binary operators (= < > * . etc) ', PHPCF_KEY_LEFT => PHPCF_EX_SHRINK_SPACES_STRONG, PHPCF_KEY_DESCR_RIGHT => 'One space after binary operators (= < > * . etc) ', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES_STRONG, ) ), 'T_DOUBLE_ARROW' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_LEFT => 'One space before "=>"', PHPCF_KEY_LEFT => PHPCF_EX_SHRINK_SPACES_STRONG, PHPCF_KEY_DESCR_RIGHT => 'One space after "=>"', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES_STRONG, ), 'CTX_INLINE_EXPR_NL_END CTX_LONG_EXPR_NL_END' => array( PHPCF_KEY_DESCR_LEFT => 'One space before "=>"', PHPCF_KEY_LEFT => PHPCF_EX_SHRINK_SPACES_STRONG, PHPCF_KEY_DESCR_RIGHT => 'One space after "=>"', PHPCF_KEY_RIGHT => array(PHPCF_EX_DECREASE_INDENT, PHPCF_EX_SHRINK_SPACES_STRONG), ) ), '+_UNARY -_UNARY &_UNARY ! @ $ ~' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_RIGHT => 'No whitespace before unary: + - & ! @ $', PHPCF_KEY_RIGHT => PHPCF_EX_DELETE_SPACES_STRONG, ), ), '._NL' => array( 'CTX_INLINE_FIRST_NL CTX_LONG_FIRST_NL' => array( PHPCF_KEY_DESCR_LEFT => 'Single space before "." in multiline concatenation', PHPCF_KEY_LEFT => PHPCF_EX_SHRINK_SPACES_STRONG, PHPCF_KEY_DESCR_RIGHT => 'Indent and newline after "." in long expression', PHPCF_KEY_RIGHT => array(PHPCF_EX_INCREASE_INDENT, PHPCF_EX_CHECK_NL) ), 'CTX_INLINE_EXPR_NL CTX_LONG_EXPR_NL' => array( PHPCF_KEY_DESCR_LEFT => 'Single space before "." in multiline concatenation', PHPCF_KEY_LEFT => PHPCF_EX_SHRINK_SPACES_STRONG, PHPCF_KEY_DESCR_RIGHT => 'Same indent and newline after "." in long expression', PHPCF_KEY_RIGHT => PHPCF_EX_CHECK_NL, ), ), ',' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before ","', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES_STRONG, PHPCF_KEY_DESCR_RIGHT => 'One space after ","', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES, ), 'CTX_CLASS_CONST_D_NL CTX_CLASS_VARIABLE_D_NL' => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before ","', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES_STRONG, PHPCF_KEY_DESCR_RIGHT => '1 newline with proper indent after "," in property definition', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_NLS, ), 'CTX_LONG_PARENTHESIS' => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before ","', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES_STRONG, PHPCF_KEY_DESCR_RIGHT => '1 newline with proper indent after "," in long expression', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_NLS, ), 'CTX_ARRAY_LONG_PARENTHESIS' => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before ","', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES_STRONG, PHPCF_KEY_DESCR_RIGHT => 'Either newline or space with proper indent after "," in long array', PHPCF_KEY_RIGHT => PHPCF_EX_NL_OR_SPACE, ), ), ',_LONG' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before ","', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES_STRONG, PHPCF_KEY_DESCR_RIGHT => 'One space after ","', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES, ), 'CTX_CLASS_CONST_D_NL CTX_CLASS_VARIABLE_D_NL' => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before ","', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES_STRONG, PHPCF_KEY_DESCR_RIGHT => '1 newline with proper indent after "," in property definition', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_NLS_STRONG, ), 'CTX_LONG_PARENTHESIS' => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before ","', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES_STRONG, PHPCF_KEY_DESCR_RIGHT => '1 newline with proper indent after "," in long expression', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_NLS, ), 'CTX_ARRAY_LONG_PARENTHESIS' => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before ","', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES_STRONG, PHPCF_KEY_DESCR_RIGHT => '1 newline with proper indent after "," in item list in array', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_NLS, ), ), '[' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before "["', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES_STRONG, PHPCF_KEY_DESCR_RIGHT => 'No whitespace after "["', PHPCF_KEY_RIGHT => PHPCF_EX_DELETE_SPACES_STRONG, ), ), ']' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before "]"', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES_STRONG, ), ), ':' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before ":"', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES, PHPCF_KEY_DESCR_RIGHT => 'No whitespace after ":"', PHPCF_KEY_RIGHT => PHPCF_EX_DELETE_SPACES, ), 'CTX_CASE_COLON' => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before ":" in "case:"', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES, PHPCF_KEY_DESCR_RIGHT => 'Indent and 1 or 2 newlines with proper indent after "case:"', PHPCF_KEY_RIGHT => array(PHPCF_EX_INCREASE_INDENT, PHPCF_EX_SHRINK_NLS), ), 'CTX_CASE_MULTI_COLON' => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before ":" in "case:" (multi colon)', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES, PHPCF_KEY_DESCR_RIGHT => 'Indent and 1 or 2 newlines with proper indent after "case:" (multi colon)', PHPCF_KEY_RIGHT => array(PHPCF_EX_INCREASE_INDENT, PHPCF_EX_SHRINK_NLS), ), 'CTX_TERNARY_OPERATOR' => array( PHPCF_KEY_DESCR_LEFT => 'One space before ":" in ternary operator ( ... ? ... : ... )', PHPCF_KEY_LEFT => PHPCF_EX_SHRINK_SPACES_STRONG, PHPCF_KEY_DESCR_RIGHT => 'One space after ":" in ternary operator ( ... ? ... : ... )', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES_STRONG, ), ), 'T_SWITCH' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_LEFT => '1 or 2 newlines with proper indent before "switch"', PHPCF_KEY_LEFT => PHPCF_EX_CHECK_NL, PHPCF_KEY_DESCR_RIGHT => 'One space after "switch"', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES_STRONG, ), ), 'T_CASE' => array( 'CTX_CASE_FIRST_D' => array( PHPCF_KEY_DESCR_LEFT => '1 newline with proper indent before first "case/default"', PHPCF_KEY_LEFT => PHPCF_EX_SHRINK_NLS, PHPCF_KEY_DESCR_RIGHT => 'One space after "case"', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES ), 'CTX_CASE_D' => array( PHPCF_KEY_DESCR_LEFT => '2 newlines with proper indent before "case"', PHPCF_KEY_LEFT => PHPCF_EX_SHRINK_NLS_2, PHPCF_KEY_DESCR_RIGHT => 'One space after "case"', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES ), 'CTX_CASE_MULTI_D' => array( PHPCF_KEY_DESCR_LEFT => '1 newline with proper indent before repeated "case"', PHPCF_KEY_LEFT => array(PHPCF_EX_DECREASE_INDENT, PHPCF_EX_SHRINK_NLS), PHPCF_KEY_DESCR_RIGHT => 'One space after "case"', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES ), 'CTX_NOBREAK_CASE_D' => array( PHPCF_KEY_DESCR_LEFT => '2 newlines with proper indent before "case" without break', PHPCF_KEY_LEFT => array(PHPCF_EX_DECREASE_INDENT, PHPCF_EX_SHRINK_NLS_2), PHPCF_KEY_DESCR_RIGHT => 'One space after "case"', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES, ), ), 'T_DEFAULT' => array( 'CTX_CASE_FIRST_D' => array( PHPCF_KEY_DESCR_LEFT => '1 newline with proper indent before first "case/default"', PHPCF_KEY_LEFT => PHPCF_EX_SHRINK_NLS, PHPCF_KEY_DESCR_RIGHT => 'No spaces after "default"', PHPCF_KEY_RIGHT => PHPCF_EX_DELETE_SPACES ), 'CTX_CASE_D' => array( PHPCF_KEY_DESCR_LEFT => '2 newlines with proper indent before "default"', PHPCF_KEY_LEFT => PHPCF_EX_SHRINK_NLS_2, PHPCF_KEY_DESCR_RIGHT => 'No spaces after "default"', PHPCF_KEY_RIGHT => PHPCF_EX_DELETE_SPACES ), 'CTX_CASE_MULTI_D' => array( PHPCF_KEY_DESCR_LEFT => '1 newline with proper indent before repeated "default"', PHPCF_KEY_LEFT => array(PHPCF_EX_DECREASE_INDENT, PHPCF_EX_SHRINK_NLS), PHPCF_KEY_DESCR_RIGHT => 'No spaces after "default"', PHPCF_KEY_RIGHT => PHPCF_EX_DELETE_SPACES ), 'CTX_NOBREAK_CASE_D' => array( PHPCF_KEY_DESCR_LEFT => '2 newlines with proper indent before "default" without break', PHPCF_KEY_LEFT => array(PHPCF_EX_DECREASE_INDENT, PHPCF_EX_SHRINK_NLS_2), PHPCF_KEY_DESCR_RIGHT => 'No spaces after "default"', PHPCF_KEY_RIGHT => PHPCF_EX_DELETE_SPACES ), ), 'T_BREAK' => array( // PHPCF_KEY_RIGHT => PHPCF_EX_DELETE_SPACES, // breaks the following construct: "break 3;" PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_LEFT => 'No whitespace before "break"', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES, ), 'CTX_IF CTX_ELSEIF CTX_ELSE' => array( PHPCF_KEY_DESCR_LEFT => '1 space before "break" in oneline "if/else/elseif"', PHPCF_KEY_LEFT => PHPCF_EX_SHRINK_SPACES_STRONG, ), 'CTX_CASE_BREAK' => array( PHPCF_KEY_DESCR_LEFT => '1 or 2 newlines with proper indent before "break"', PHPCF_KEY_LEFT => PHPCF_EX_SHRINK_NLS, PHPCF_KEY_DESCR_RIGHT => 'Indent and no whitespace before break', PHPCF_KEY_RIGHT => array(PHPCF_EX_DECREASE_INDENT), ), ), 'T_ECHO T_RETURN' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_RIGHT => 'One space after "echo" and "return"', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES_STRONG, ), ), 'T_FUNCTION' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_RIGHT => 'One space after "function"', PHPCF_KEY_RIGHT => PHPCF_EX_SHRINK_SPACES, ), ), // $a--, $b++ 'T_INC_RIGHT T_DEC_RIGHT' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_LEFT => 'No whitespaces in "$c++" and type casts', PHPCF_KEY_LEFT => PHPCF_EX_DELETE_SPACES, ), ), // --$a, --$b 'T_INC_LEFT T_DEC_LEFT ' . $casts => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_RIGHT => 'No whitespaces in "++$c" and type casts', PHPCF_KEY_RIGHT => PHPCF_EX_DELETE_SPACES, ), ), /* DO NOT CHANGE rules for comments unless you really know what you are doing */ 'T_SINGLE_LINE_COMMENT' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_LEFT => 'One space in comment after expression', PHPCF_KEY_LEFT => PHPCF_EX_DO_NOT_TOUCH_ANYTHING, PHPCF_KEY_DESCR_RIGHT => 'New line after single-line comment', PHPCF_KEY_RIGHT => PHPCF_EX_CHECK_NL_STRONG, ) ), 'T_SINGLE_LINE_COMMENT_ALONE' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_RIGHT => 'New line after single-line comment', PHPCF_KEY_RIGHT => PHPCF_EX_CHECK_NL_STRONG, ), ), /* / DO NOT CHANGE */ 'T_OPEN_TAG' => array( PHPCF_KEY_ALL => array( PHPCF_KEY_DESCR_RIGHT => 'New line after opening tag', PHPCF_KEY_RIGHT => PHPCF_EX_CHECK_NL_STRONG, ) ) ); $fsm_parenthesis_rules = array( '(_LONG' => array('CTX_LONG_PARENTHESIS'), '(' => array('CTX_GENERIC_PARENTHESIS'), ); $fsm_inline_rules = $fsm_parenthesis_rules + array( '?' => array('CTX_TERNARY_BEGIN'), 'T_OBJECT_OPERATOR' => array('CTX_INLINE_BRACE_BEGIN'), '$' => array('CTX_INLINE_BRACE_BEGIN'), '._NL' => array('CTX_INLINE_FIRST_NL'), 'T_ARRAY' => array('CTX_ARRAY'), ); $fsm_generic_code_rules = array( 'T_CLOSE_TAG' => 'CTX_DEFAULT', 'T_FINAL' => array('CTX_CLASS_D'), 'T_ABSTRACT' => array('CTX_CLASS_D'), 'T_CLASS' => array('CTX_CLASS_D'), 'T_INTERFACE' => array('CTX_CLASS_D'), 'T_FUNCTION' => array('CTX_FUNCTION_D'), 'T_SWITCH' => array('CTX_SWITCH'), 'T_WHILE' => array('CTX_WHILE'), 'T_FOREACH' => array('CTX_FOREACH'), 'T_FOR' => array('CTX_FOR'), 'T_DO' => array('CTX_DO'), 'T_IF' => array('CTX_IF'), 'T_ELSEIF' => array('CTX_ELSEIF'), 'T_ELSE' => array('CTX_ELSE'), 'T_CASE' => array('CTX_CASE_FIRST_D'), 'T_DEFAULT' => array('CTX_CASE_FIRST_D'), ) + $fsm_inline_rules; $fsm_generic_code_block_rules = $fsm_generic_code_rules + array('}' => -1, '{' => array('CTX_GENERIC_BLOCK')); $fsm_context_rules_switch = array( 'CTX_SWITCH' => array( '{' => 'CTX_GENERIC_BLOCK', ), 'CTX_SWITCH_BLOCK' => array( 'T_CASE' => array('CTX_CASE_D'), 'T_DEFAULT' => array('CTX_CASE_D'), ) + $fsm_generic_code_block_rules, 'CTX_CASE_D CTX_CASE_FIRST_D CTX_NOBREAK_CASE_D' => array( ':' => 'CTX_CASE_MULTI_COLON', ), 'CTX_CASE_MULTI_D' => array( ':' => 'CTX_CASE_MULTI_COLON', ), 'CTX_CASE_MULTI_COLON' => array( 'T_CASE' => 'CTX_CASE_MULTI_D', 'T_DEFAULT' => 'CTX_CASE_MULTI_D', 'T_BREAK' => 'CTX_CASE_BREAK', PHPCF_KEY_ALL => 'CTX_CASE', ), 'CTX_CASE' => array( 'T_CASE' => 'CTX_NOBREAK_CASE_D', 'T_DEFAULT' => 'CTX_NOBREAK_CASE_D', 'T_BREAK' => 'CTX_CASE_BREAK', '}' => array(PHPCF_CTX_NOW => 'CTX_CASE_END_OF_BLOCK', PHPCF_CTX_NEXT => -2), ) + $fsm_generic_code_block_rules, 'CTX_CASE_BREAK' => array( ';' => array(PHPCF_CTX_NOW => -1, PHPCF_CTX_NEXT => 'CTX_SWITCH_BLOCK',), ), ); $fsm_context_rules_loops = array( 'CTX_WHILE' => array( '{' => 'CTX_GENERIC_BLOCK', ';' => -1 ) + $fsm_inline_rules, 'CTX_FOREACH' => array( '{' => 'CTX_GENERIC_BLOCK', ';' => -1 ) + $fsm_inline_rules, 'CTX_FOR' => array( '(' => 'CTX_FOR_PARENTHESIS', '(_LONG' => 'CTX_FOR_PARENTHESIS', ), 'CTX_DO' => array( '{' => array('CTX_GENERIC_BLOCK'), 'T_WHILE' => 'CTX_WHILE_AFTER_DO', PHPCF_KEY_ALL => -1 ), 'CTX_WHILE_AFTER_DO' => array( ';' => -1, ), ); $fsm_context_rules_parenthesis = array( 'CTX_FOR_PARENTHESIS' => array( ')' => -1, ) + $fsm_inline_rules, 'CTX_GENERIC_PARENTHESIS' => array( ')' => -1, ) + $fsm_inline_rules, 'CTX_LONG_PARENTHESIS CTX_ARRAY_LONG_PARENTHESIS' => array( ')' => array(PHPCF_CTX_NOW => 'CTX_LONG_PAR_END', PHPCF_CTX_NEXT => -1), '._NL' => array('CTX_LONG_FIRST_NL'), ) + $fsm_inline_rules, ); $fsm_context_rules_conditions = array( 'CTX_IF CTX_ELSEIF' => array( '(_LONG' => array('CTX_GENERIC_PARENTHESIS'), '{' => 'CTX_GENERIC_BLOCK', ';' => -1, ) + $fsm_inline_rules, 'CTX_ELSE' => array( '{' => 'CTX_GENERIC_BLOCK', ';' => -1, ), 'CTX_TERNARY_BEGIN' => array( ':' => array(PHPCF_CTX_NOW => 'CTX_TERNARY_OPERATOR', PHPCF_CTX_NEXT => -1), ) + $fsm_inline_rules, ); $fsm_context_rules_array = array( 'CTX_ARRAY' => array( '(_LONG' => 'CTX_ARRAY_LONG_PARENTHESIS', '(' => 'CTX_GENERIC_PARENTHESIS', ), ); $fsm_context_rules_class = array( 'CTX_CLASS_D' => array( '{' => array(PHPCF_CTX_NOW => 'CTX_CLASS_D', PHPCF_CTX_NEXT => 'CTX_CLASS'), ), 'CTX_CLASS' => array( 'T_PUBLIC' => array('CTX_CLASS_DEF'), 'T_CONST' => array('CTX_CLASS_DEF'), 'T_PRIVATE' => array('CTX_CLASS_DEF'), 'T_PROTECTED' => array('CTX_CLASS_DEF'), 'T_STATIC' => array('CTX_CLASS_DEF'), 'T_CONST' => array('CTX_CLASS_DEF'), 'T_FINAL' => array('CTX_CLASS_DEF'), 'T_ABSTRACT' => array('CTX_CLASS_DEF'), 'T_PUBLIC_NL' => array('CTX_CLASS_DEF_NL'), 'T_CONST_NL' => array('CTX_CLASS_DEF_NL'), 'T_PRIVATE_NL' => array('CTX_CLASS_DEF_NL'), 'T_PROTECTED_NL' => array('CTX_CLASS_DEF_NL'), 'T_STATIC_NL' => array('CTX_CLASS_DEF_NL'), 'T_CONST_NL' => array('CTX_CLASS_DEF_NL'), 'T_FINAL' => array('CTX_CLASS_DEF_NL'), 'T_VAR' => array('CTX_CLASS_VARIABLE_D'), 'T_FUNCTION' => array('CTX_CLASS_METHOD_D'), '}' => -1, ), 'CTX_CLASS_DEF' => array( 'T_FUNCTION' => 'CTX_CLASS_METHOD_D', 'T_CONST' => 'CTX_CLASS_CONST_D', 'T_VARIABLE' => 'CTX_CLASS_VARIABLE_D', 'T_PUBLIC_NL' => 'CTX_CLASS_DEF_NL', 'T_CONST_NL' => 'CTX_CLASS_DEF_NL', 'T_PRIVATE_NL' => 'CTX_CLASS_DEF_NL', 'T_PROTECTED_NL' => 'CTX_CLASS_DEF_NL', 'T_STATIC_NL' => 'CTX_CLASS_DEF_NL', 'T_CONST_NL' => 'CTX_CLASS_DEF_NL', 'T_FINAL' => 'CTX_CLASS_DEF_NL', ), 'CTX_CLASS_DEF_NL' => array( 'T_FUNCTION' => 'CTX_CLASS_METHOD_D_NL', 'T_STRING' => 'CTX_CLASS_CONST_D_NL', 'T_VARIABLE' => 'CTX_CLASS_VARIABLE_D_NL', ), 'CTX_CLASS_CONST_D' => array( 'T_STRING' => 'CTX_CLASS_CONST', ), 'CTX_CLASS_CONST_D_NL' => array( 'T_STRING' => 'CTX_CLASS_CONST_NL', ), 'CTX_CLASS_CONST' => array( ';' => -1, ), 'CTX_CLASS_CONST_NL' => array( ';' => array(PHPCF_CTX_NOW => 'CTX_CLASS_CONST_NL_END', PHPCF_CTX_NEXT => -1) ), 'CTX_CLASS_VARIABLE_D' => array( ';' => -1, ) + $fsm_inline_rules, 'CTX_CLASS_VARIABLE_D_NL' => array( ';' => array(PHPCF_CTX_NOW => 'CTX_CLASS_VARIABLE_D_NL_END', PHPCF_CTX_NEXT => -1) ) + $fsm_inline_rules, 'CTX_CLASS_METHOD_D CTX_CLASS_METHOD_D_NL' => array( '{' => array(PHPCF_CTX_NOW => 'CTX_CLASS_METHOD_D', PHPCF_CTX_NEXT => 'CTX_CLASS_METHOD'), ), 'CTX_FUNCTION_D' => array( '{' => array(PHPCF_CTX_NOW => 'CTX_FUNCTION_D', PHPCF_CTX_NEXT => 'CTX_FUNCTION'), ), 'CTX_CLASS_METHOD' => array('}' => -1) + $fsm_generic_code_block_rules, 'CTX_FUNCTION' => $fsm_generic_code_block_rules, ); $fsm_context_rules = array( 0 => 'CTX_DEFAULT', 'CTX_DEFAULT' => array( 'T_OPEN_TAG' => 'CTX_PHP', 'T_OPEN_TAG_WITH_ECHO' => 'CTX_PHP', ), 'CTX_PHP' => $fsm_generic_code_rules, 'CTX_INLINE_BRACE_BEGIN' => array( '{' => 'CTX_INLINE_BRACE', PHPCF_KEY_ALL => -1, ), 'CTX_INLINE_BRACE' => array( '}' => array(PHPCF_CTX_NOW => 'CTX_INLINE_BRACE', PHPCF_CTX_NEXT => -1), ), 'CTX_GENERIC_BLOCK' => $fsm_generic_code_block_rules, 'CTX_LONG_FIRST_NL CTX_LONG_EXPR_NL' => array( '._NL' => 'CTX_LONG_EXPR_NL', 'T_DOUBLE_ARROW' => array(PHPCF_CTX_NOW => 'CTX_INLINE_EXPR_NL_END', PHPCF_CTX_NEXT => -1), ')' => array(PHPCF_CTX_NOW => 'CTX_LONG_EXPR_NL_END', PHPCF_CTX_NEXT => -2), ) + $fsm_inline_rules, 'CTX_INLINE_FIRST_NL CTX_INLINE_EXPR_NL' => array( '._NL' => 'CTX_INLINE_EXPR_NL', ')' => array(PHPCF_CTX_NOW => 'CTX_INLINE_EXPR_NL_END', PHPCF_CTX_NEXT => -1), ';' => array(PHPCF_CTX_NOW => 'CTX_INLINE_EXPR_NL_END', PHPCF_CTX_NEXT => -1), 'T_DOUBLE_ARROW' => array(PHPCF_CTX_NOW => 'CTX_INLINE_EXPR_NL_END', PHPCF_CTX_NEXT => -1), ) + $fsm_inline_rules, ); $fsm_context_rules += $fsm_context_rules_parenthesis; $fsm_context_rules += $fsm_context_rules_conditions; $fsm_context_rules += $fsm_context_rules_loops; $fsm_context_rules += $fsm_context_rules_switch; $fsm_context_rules += $fsm_context_rules_array; $fsm_context_rules += $fsm_context_rules_class; // print_r($fsm_context_rules); $options = array( 'debug' => 0, 'quiet' => 0, 'summary' => 0, 'check' => 0, 'preview' => 0, 'apply' => 0, 'lines' => null, ); foreach ($argv as $k => $v) { if ($v === '--debug' || $v === '-d') { unset($argv[$k]); $options['debug'] = 1; } if ($v === '--quiet' || $v === '-q') { unset($argv[$k]); $options['quiet'] = 1; } if ($v === '--summary' || $v === '-s') { unset($argv[$k]); $options['summary'] = 1; } $arg = '--lines='; if (substr($v, 0, strlen($arg)) == $arg) { $lines_str = substr($argv[$k], strlen($arg)); $options['lines'] = $lines_str; unset($argv[$k]); } } $argv = array_values($argv); $argc = count($argv); if ($argc < 3 || !isset($options[$argv[1]])) { if ($argc > 1 && !isset($options[$argv[1]])) { fwrite(STDERR, "ERROR: Unknown command: " . $argv[1] . "\n\n"); } fwrite(STDERR, "Usage: $argv[0] [<flags>] <command> <filename> [ ... <filename>]\n\n"); fwrite(STDERR, "Flags:\n"); fwrite(STDERR, " --debug turn on debug mode\n"); fwrite(STDERR, " --quiet do not print status messages\n"); fwrite(STDERR, " --summary show only number of formatting error messages (if any)\n"); fwrite(STDERR, " --lines=... comma-separated list of line numbers to format instead of all file\n\n"); fwrite(STDERR, "Commands:\n"); fwrite(STDERR, " check just check a file and report about problems with non-zero exit code\n"); fwrite(STDERR, " apply format file, overwrite it and print report\n"); fwrite(STDERR, " preview show diff between original and suggested format and print report\n"); exit(1); } $options[$argv[1]] = 1; define('PHPCF_DEBUG', $options['debug']); define('PHPCF_SNIFF', true); define('PHPCF_APPLY', $options['apply']); define('PHPCF_PREVIEW', $options['preview']); define('PHPCF_SUMMARY', $options['summary']); function phpcf_format_file($filename, $fsm_context_rules, $controls, $options, $lock = false) { if ($lock) $fp = fopen($lock, 'w+'); $F = new PHPCodeFormatter($filename, $fsm_context_rules, $controls); $F->process(); $lines = null; if (isset($options['lines'])) { $lines = strlen($options['lines']) ? array_flip(explode(',', $options['lines'])) : array(); } $formatted = $F->exec($lines); if ($lock) flock($fp, LOCK_EX); if ($F->sniff_exit_code) fwrite(STDERR, "Errors for $filename:\n"); $F->printSnifferMessages($options['lines']); if (PHPCF_PREVIEW) { $tmpnam = tempnam('/tmp', 'phpcf'); if (!$tmpnam) return false; if (!file_put_contents($tmpnam, $formatted)) return false; system('diff -u ' . escapeshellarg($filename) . ' ' . $tmpnam . ' | cdiff'); if (file_exists($tmpnam)) unlink($tmpnam); } if (PHPCF_APPLY) { $success = file_put_contents($filename, $formatted); if (!$options['quiet'] && $success !== false) { echo "$filename formatted successfully\n"; } if ($success === false) { fwrite(STDERR, "Could not format $filename\n"); return false; } } if (PHPCF_SNIFF) { if (!$F->sniff_exit_code && !$options['quiet'] && !PHPCF_APPLY) { echo "$filename is OK\n"; } } if ($options['check'] && $F->sniff_exit_code) return false; return true; } if (function_exists('pcntl_fork')) { $lock = tempnam('/tmp', 'phpcf-lock'); $children = 0; for ($i = 2; $i < $argc; $i++) { $filename = $argv[$i]; $pid = pcntl_fork(); if ($pid > 0) $children++; if ($pid == 0) exit(phpcf_format_file($filename, $fsm_context_rules, $controls, $options, $lock) ? 0 : 1); } $fp = fopen($lock, 'w+'); $children_status = 0; $success = true; for ($i = 0; $i < $children; $i++) { pcntl_wait($children_status); if (pcntl_wexitstatus($children_status)) $success = false; } fclose($fp); unlink($lock); } else { $success = true; for ($i = 2; $i < $argc; $i++) { $filename = $argv[$i]; if (!phpcf_format_file($filename, $fsm_context_rules, $controls, $options)) $success = false; } } exit($success ? 0 : 1);