+ * 0 => array(
+ * 'name' => '$var', // The variable name.
+ * 'token' => integer, // The stack pointer to the variable name.
+ * 'content' => string, // The full content of the variable definition.
+ * 'pass_by_reference' => boolean, // Is the variable passed by reference?
+ * 'variable_length' => boolean, // Is the param of variable length through use of `...` ?
+ * 'type_hint' => string, // The type hint for the variable.
+ * 'nullable_type' => boolean, // Is the variable using a nullable type?
+ * )
+ *
+ *
+ * Parameters with default values have an additional array index of
+ * 'default' with the value of the default as a string.
+ *
+ * @param int $stackPtr The position in the stack of the function token
+ * to acquire the parameters for.
+ *
+ * @return array
+ * @throws \PHP_CodeSniffer\Exceptions\TokenizerException If the specified $stackPtr is not of
+ * type T_FUNCTION or T_CLOSURE.
+ */
+ public function getMethodParameters($stackPtr)
+ {
+ if ($this->tokens[$stackPtr]['code'] !== T_FUNCTION
+ && $this->tokens[$stackPtr]['code'] !== T_CLOSURE
+ ) {
+ throw new TokenizerException('$stackPtr must be of type T_FUNCTION or T_CLOSURE');
+ }
+
+ $opener = $this->tokens[$stackPtr]['parenthesis_opener'];
+ $closer = $this->tokens[$stackPtr]['parenthesis_closer'];
+
+ $vars = array();
+ $currVar = null;
+ $paramStart = ($opener + 1);
+ $defaultStart = null;
+ $paramCount = 0;
+ $passByReference = false;
+ $variableLength = false;
+ $typeHint = '';
+ $nullableType = false;
+
+ for ($i = $paramStart; $i <= $closer; $i++) {
+ // Check to see if this token has a parenthesis or bracket opener. If it does
+ // it's likely to be an array which might have arguments in it. This
+ // could cause problems in our parsing below, so lets just skip to the
+ // end of it.
+ if (isset($this->tokens[$i]['parenthesis_opener']) === true) {
+ // Don't do this if it's the close parenthesis for the method.
+ if ($i !== $this->tokens[$i]['parenthesis_closer']) {
+ $i = ($this->tokens[$i]['parenthesis_closer'] + 1);
+ }
+ }
+
+ if (isset($this->tokens[$i]['bracket_opener']) === true) {
+ // Don't do this if it's the close parenthesis for the method.
+ if ($i !== $this->tokens[$i]['bracket_closer']) {
+ $i = ($this->tokens[$i]['bracket_closer'] + 1);
+ }
+ }
+
+ switch ($this->tokens[$i]['code']) {
+ case T_BITWISE_AND:
+ if ($defaultStart === null) {
+ $passByReference = true;
+ }
+ break;
+ case T_VARIABLE:
+ $currVar = $i;
+ break;
+ case T_ELLIPSIS:
+ $variableLength = true;
+ break;
+ case T_ARRAY_HINT:
+ case T_CALLABLE:
+ $typeHint .= $this->tokens[$i]['content'];
+ break;
+ case T_SELF:
+ case T_PARENT:
+ case T_STATIC:
+ // Self is valid, the others invalid, but were probably intended as type hints.
+ if (isset($defaultStart) === false) {
+ $typeHint .= $this->tokens[$i]['content'];
+ }
+ break;
+ case T_STRING:
+ // This is a string, so it may be a type hint, but it could
+ // also be a constant used as a default value.
+ $prevComma = false;
+ for ($t = $i; $t >= $opener; $t--) {
+ if ($this->tokens[$t]['code'] === T_COMMA) {
+ $prevComma = $t;
+ break;
+ }
+ }
+
+ if ($prevComma !== false) {
+ $nextEquals = false;
+ for ($t = $prevComma; $t < $i; $t++) {
+ if ($this->tokens[$t]['code'] === T_EQUAL) {
+ $nextEquals = $t;
+ break;
+ }
+ }
+
+ if ($nextEquals !== false) {
+ break;
+ }
+ }
+
+ if ($defaultStart === null) {
+ $typeHint .= $this->tokens[$i]['content'];
+ }
+ break;
+ case T_NS_SEPARATOR:
+ // Part of a type hint or default value.
+ if ($defaultStart === null) {
+ $typeHint .= $this->tokens[$i]['content'];
+ }
+ break;
+ case T_NULLABLE:
+ if ($defaultStart === null) {
+ $nullableType = true;
+ $typeHint .= $this->tokens[$i]['content'];
+ }
+ break;
+ case T_CLOSE_PARENTHESIS:
+ case T_COMMA:
+ // If it's null, then there must be no parameters for this
+ // method.
+ if ($currVar === null) {
+ continue;
+ }
+
+ $vars[$paramCount] = array();
+ $vars[$paramCount]['token'] = $currVar;
+ $vars[$paramCount]['name'] = $this->tokens[$currVar]['content'];
+ $vars[$paramCount]['content'] = trim($this->getTokensAsString($paramStart, ($i - $paramStart)));
+
+ if ($defaultStart !== null) {
+ $vars[$paramCount]['default'] = trim($this->getTokensAsString($defaultStart, ($i - $defaultStart)));
+ }
+
+ $vars[$paramCount]['pass_by_reference'] = $passByReference;
+ $vars[$paramCount]['variable_length'] = $variableLength;
+ $vars[$paramCount]['type_hint'] = $typeHint;
+ $vars[$paramCount]['nullable_type'] = $nullableType;
+
+ // Reset the vars, as we are about to process the next parameter.
+ $defaultStart = null;
+ $paramStart = ($i + 1);
+ $passByReference = false;
+ $variableLength = false;
+ $typeHint = '';
+ $nullableType = false;
+
+ $paramCount++;
+ break;
+ case T_EQUAL:
+ $defaultStart = ($i + 1);
+ break;
+ }//end switch
+ }//end for
+
+ return $vars;
+
+ }//end getMethodParameters()
+
+
+ /**
+ * Returns the visibility and implementation properties of a method.
+ *
+ * The format of the array is:
+ *
+ * array(
+ * 'scope' => 'public', // public protected or protected
+ * 'scope_specified' => true, // true is scope keyword was found.
+ * 'is_abstract' => false, // true if the abstract keyword was found.
+ * 'is_final' => false, // true if the final keyword was found.
+ * 'is_static' => false, // true if the static keyword was found.
+ * );
+ *
+ *
+ * @param int $stackPtr The position in the stack of the function token to
+ * acquire the properties for.
+ *
+ * @return array
+ * @throws \PHP_CodeSniffer\Exceptions\TokenizerException If the specified position is not a
+ * T_FUNCTION token.
+ */
+ public function getMethodProperties($stackPtr)
+ {
+ if ($this->tokens[$stackPtr]['code'] !== T_FUNCTION
+ && $this->tokens[$stackPtr]['code'] !== T_CLOSURE
+ ) {
+ throw new TokenizerException('$stackPtr must be of type T_FUNCTION or T_CLOSURE');
+ }
+
+ if ($this->tokens[$stackPtr]['code'] === T_FUNCTION) {
+ $valid = array(
+ T_PUBLIC => T_PUBLIC,
+ T_PRIVATE => T_PRIVATE,
+ T_PROTECTED => T_PROTECTED,
+ T_STATIC => T_STATIC,
+ T_FINAL => T_FINAL,
+ T_ABSTRACT => T_ABSTRACT,
+ T_WHITESPACE => T_WHITESPACE,
+ T_COMMENT => T_COMMENT,
+ T_DOC_COMMENT => T_DOC_COMMENT,
+ );
+ } else {
+ $valid = array(
+ T_STATIC => T_STATIC,
+ T_WHITESPACE => T_WHITESPACE,
+ T_COMMENT => T_COMMENT,
+ T_DOC_COMMENT => T_DOC_COMMENT,
+ );
+ }
+
+ $scope = 'public';
+ $scopeSpecified = false;
+ $isAbstract = false;
+ $isFinal = false;
+ $isStatic = false;
+
+ for ($i = ($stackPtr - 1); $i > 0; $i--) {
+ if (isset($valid[$this->tokens[$i]['code']]) === false) {
+ break;
+ }
+
+ switch ($this->tokens[$i]['code']) {
+ case T_PUBLIC:
+ $scope = 'public';
+ $scopeSpecified = true;
+ break;
+ case T_PRIVATE:
+ $scope = 'private';
+ $scopeSpecified = true;
+ break;
+ case T_PROTECTED:
+ $scope = 'protected';
+ $scopeSpecified = true;
+ break;
+ case T_ABSTRACT:
+ $isAbstract = true;
+ break;
+ case T_FINAL:
+ $isFinal = true;
+ break;
+ case T_STATIC:
+ $isStatic = true;
+ break;
+ }//end switch
+ }//end for
+
+ return array(
+ 'scope' => $scope,
+ 'scope_specified' => $scopeSpecified,
+ 'is_abstract' => $isAbstract,
+ 'is_final' => $isFinal,
+ 'is_static' => $isStatic,
+ );
+
+ }//end getMethodProperties()
+
+
+ /**
+ * Returns the visibility and implementation properties of the class member
+ * variable found at the specified position in the stack.
+ *
+ * The format of the array is:
+ *
+ *
+ * array(
+ * 'scope' => 'public', // public protected or protected
+ * 'is_static' => false, // true if the static keyword was found.
+ * );
+ *
+ *
+ * @param int $stackPtr The position in the stack of the T_VARIABLE token to
+ * acquire the properties for.
+ *
+ * @return array
+ * @throws \PHP_CodeSniffer\Exceptions\TokenizerException If the specified position is not a
+ * T_VARIABLE token, or if the position is not
+ * a class member variable.
+ */
+ public function getMemberProperties($stackPtr)
+ {
+ if ($this->tokens[$stackPtr]['code'] !== T_VARIABLE) {
+ throw new TokenizerException('$stackPtr must be of type T_VARIABLE');
+ }
+
+ $conditions = array_keys($this->tokens[$stackPtr]['conditions']);
+ $ptr = array_pop($conditions);
+ if (isset($this->tokens[$ptr]) === false
+ || ($this->tokens[$ptr]['code'] !== T_CLASS
+ && $this->tokens[$ptr]['code'] !== T_ANON_CLASS
+ && $this->tokens[$ptr]['code'] !== T_TRAIT)
+ ) {
+ if (isset($this->tokens[$ptr]) === true
+ && $this->tokens[$ptr]['code'] === T_INTERFACE
+ ) {
+ // T_VARIABLEs in interfaces can actually be method arguments
+ // but they wont be seen as being inside the method because there
+ // are no scope openers and closers for abstract methods. If it is in
+ // parentheses, we can be pretty sure it is a method argument.
+ if (isset($this->tokens[$stackPtr]['nested_parenthesis']) === false
+ || empty($this->tokens[$stackPtr]['nested_parenthesis']) === true
+ ) {
+ $error = 'Possible parse error: interfaces may not include member vars';
+ $this->addWarning($error, $stackPtr, 'Internal.ParseError.InterfaceHasMemberVar');
+ return array();
+ }
+ } else {
+ throw new TokenizerException('$stackPtr is not a class member var');
+ }
+ }
+
+ $valid = array(
+ T_PUBLIC => T_PUBLIC,
+ T_PRIVATE => T_PRIVATE,
+ T_PROTECTED => T_PROTECTED,
+ T_STATIC => T_STATIC,
+ T_WHITESPACE => T_WHITESPACE,
+ T_COMMENT => T_COMMENT,
+ T_DOC_COMMENT => T_DOC_COMMENT,
+ T_VARIABLE => T_VARIABLE,
+ T_COMMA => T_COMMA,
+ );
+
+ $scope = 'public';
+ $scopeSpecified = false;
+ $isStatic = false;
+
+ for ($i = ($stackPtr - 1); $i > 0; $i--) {
+ if (isset($valid[$this->tokens[$i]['code']]) === false) {
+ break;
+ }
+
+ switch ($this->tokens[$i]['code']) {
+ case T_PUBLIC:
+ $scope = 'public';
+ $scopeSpecified = true;
+ break;
+ case T_PRIVATE:
+ $scope = 'private';
+ $scopeSpecified = true;
+ break;
+ case T_PROTECTED:
+ $scope = 'protected';
+ $scopeSpecified = true;
+ break;
+ case T_STATIC:
+ $isStatic = true;
+ break;
+ }
+ }//end for
+
+ return array(
+ 'scope' => $scope,
+ 'scope_specified' => $scopeSpecified,
+ 'is_static' => $isStatic,
+ );
+
+ }//end getMemberProperties()
+
+
+ /**
+ * Returns the visibility and implementation properties of a class.
+ *
+ * The format of the array is:
+ *
+ * array(
+ * 'is_abstract' => false, // true if the abstract keyword was found.
+ * 'is_final' => false, // true if the final keyword was found.
+ * );
+ *
+ *
+ * @param int $stackPtr The position in the stack of the T_CLASS token to
+ * acquire the properties for.
+ *
+ * @return array
+ * @throws \PHP_CodeSniffer\Exceptions\TokenizerException If the specified position is not a
+ * T_CLASS token.
+ */
+ public function getClassProperties($stackPtr)
+ {
+ if ($this->tokens[$stackPtr]['code'] !== T_CLASS) {
+ throw new TokenizerException('$stackPtr must be of type T_CLASS');
+ }
+
+ $valid = array(
+ T_FINAL => T_FINAL,
+ T_ABSTRACT => T_ABSTRACT,
+ T_WHITESPACE => T_WHITESPACE,
+ T_COMMENT => T_COMMENT,
+ T_DOC_COMMENT => T_DOC_COMMENT,
+ );
+
+ $isAbstract = false;
+ $isFinal = false;
+
+ for ($i = ($stackPtr - 1); $i > 0; $i--) {
+ if (isset($valid[$this->tokens[$i]['code']]) === false) {
+ break;
+ }
+
+ switch ($this->tokens[$i]['code']) {
+ case T_ABSTRACT:
+ $isAbstract = true;
+ break;
+
+ case T_FINAL:
+ $isFinal = true;
+ break;
+ }
+ }//end for
+
+ return array(
+ 'is_abstract' => $isAbstract,
+ 'is_final' => $isFinal,
+ );
+
+ }//end getClassProperties()
+
+
+ /**
+ * Determine if the passed token is a reference operator.
+ *
+ * Returns true if the specified token position represents a reference.
+ * Returns false if the token represents a bitwise operator.
+ *
+ * @param int $stackPtr The position of the T_BITWISE_AND token.
+ *
+ * @return boolean
+ */
+ public function isReference($stackPtr)
+ {
+ if ($this->tokens[$stackPtr]['code'] !== T_BITWISE_AND) {
+ return false;
+ }
+
+ $tokenBefore = $this->findPrevious(
+ Util\Tokens::$emptyTokens,
+ ($stackPtr - 1),
+ null,
+ true
+ );
+
+ if ($this->tokens[$tokenBefore]['code'] === T_FUNCTION) {
+ // Function returns a reference.
+ return true;
+ }
+
+ if ($this->tokens[$tokenBefore]['code'] === T_DOUBLE_ARROW) {
+ // Inside a foreach loop or array assignment, this is a reference.
+ return true;
+ }
+
+ if ($this->tokens[$tokenBefore]['code'] === T_AS) {
+ // Inside a foreach loop, this is a reference.
+ return true;
+ }
+
+ if (isset(Util\Tokens::$assignmentTokens[$this->tokens[$tokenBefore]['code']]) === true) {
+ // This is directly after an assignment. It's a reference. Even if
+ // it is part of an operation, the other tests will handle it.
+ return true;
+ }
+
+ $tokenAfter = $this->findNext(
+ Util\Tokens::$emptyTokens,
+ ($stackPtr + 1),
+ null,
+ true
+ );
+
+ if ($this->tokens[$tokenAfter]['code'] === T_NEW) {
+ return true;
+ }
+
+ if (isset($this->tokens[$stackPtr]['nested_parenthesis']) === true) {
+ $brackets = $this->tokens[$stackPtr]['nested_parenthesis'];
+ $lastBracket = array_pop($brackets);
+ if (isset($this->tokens[$lastBracket]['parenthesis_owner']) === true) {
+ $owner = $this->tokens[$this->tokens[$lastBracket]['parenthesis_owner']];
+ if ($owner['code'] === T_FUNCTION
+ || $owner['code'] === T_CLOSURE
+ ) {
+ $params = $this->getMethodParameters($this->tokens[$lastBracket]['parenthesis_owner']);
+ foreach ($params as $param) {
+ $varToken = $tokenAfter;
+ if ($param['variable_length'] === true) {
+ $varToken = $this->findNext(
+ (Util\Tokens::$emptyTokens + array(T_ELLIPSIS)),
+ ($stackPtr + 1),
+ null,
+ true
+ );
+ }
+
+ if ($param['token'] === $varToken
+ && $param['pass_by_reference'] === true
+ ) {
+ // Function parameter declared to be passed by reference.
+ return true;
+ }
+ }
+ }//end if
+ } else {
+ $prev = false;
+ for ($t = ($this->tokens[$lastBracket]['parenthesis_opener'] - 1); $t >= 0; $t--) {
+ if ($this->tokens[$t]['code'] !== T_WHITESPACE) {
+ $prev = $t;
+ break;
+ }
+ }
+
+ if ($prev !== false && $this->tokens[$prev]['code'] === T_USE) {
+ // Closure use by reference.
+ return true;
+ }
+ }//end if
+ }//end if
+
+ // Pass by reference in function calls and assign by reference in arrays.
+ if ($this->tokens[$tokenBefore]['code'] === T_OPEN_PARENTHESIS
+ || $this->tokens[$tokenBefore]['code'] === T_COMMA
+ || $this->tokens[$tokenBefore]['code'] === T_OPEN_SHORT_ARRAY
+ ) {
+ if ($this->tokens[$tokenAfter]['code'] === T_VARIABLE) {
+ return true;
+ } else {
+ $skip = Util\Tokens::$emptyTokens;
+ $skip[] = T_NS_SEPARATOR;
+ $skip[] = T_SELF;
+ $skip[] = T_PARENT;
+ $skip[] = T_STATIC;
+ $skip[] = T_STRING;
+ $skip[] = T_NAMESPACE;
+ $skip[] = T_DOUBLE_COLON;
+
+ $nextSignificantAfter = $this->findNext(
+ $skip,
+ ($stackPtr + 1),
+ null,
+ true
+ );
+ if ($this->tokens[$nextSignificantAfter]['code'] === T_VARIABLE) {
+ return true;
+ }
+ }//end if
+ }//end if
+
+ return false;
+
+ }//end isReference()
+
+
+ /**
+ * Returns the content of the tokens from the specified start position in
+ * the token stack for the specified length.
+ *
+ * @param int $start The position to start from in the token stack.
+ * @param int $length The length of tokens to traverse from the start pos.
+ *
+ * @return string The token contents.
+ */
+ public function getTokensAsString($start, $length)
+ {
+ $str = '';
+ $end = ($start + $length);
+ if ($end > $this->numTokens) {
+ $end = $this->numTokens;
+ }
+
+ for ($i = $start; $i < $end; $i++) {
+ $str .= $this->tokens[$i]['content'];
+ }
+
+ return $str;
+
+ }//end getTokensAsString()
+
+
+ /**
+ * Returns the position of the previous specified token(s).
+ *
+ * If a value is specified, the previous token of the specified type(s)
+ * containing the specified value will be returned.
+ *
+ * Returns false if no token can be found.
+ *
+ * @param int|array $types The type(s) of tokens to search for.
+ * @param int $start The position to start searching from in the
+ * token stack.
+ * @param int $end The end position to fail if no token is found.
+ * if not specified or null, end will default to
+ * the start of the token stack.
+ * @param bool $exclude If true, find the previous token that is NOT of
+ * the types specified in $types.
+ * @param string $value The value that the token(s) must be equal to.
+ * If value is omitted, tokens with any value will
+ * be returned.
+ * @param bool $local If true, tokens outside the current statement
+ * will not be checked. IE. checking will stop
+ * at the previous semi-colon found.
+ *
+ * @return int|bool
+ * @see findNext()
+ */
+ public function findPrevious(
+ $types,
+ $start,
+ $end=null,
+ $exclude=false,
+ $value=null,
+ $local=false
+ ) {
+ $types = (array) $types;
+
+ if ($end === null) {
+ $end = 0;
+ }
+
+ for ($i = $start; $i >= $end; $i--) {
+ $found = (bool) $exclude;
+ foreach ($types as $type) {
+ if ($this->tokens[$i]['code'] === $type) {
+ $found = !$exclude;
+ break;
+ }
+ }
+
+ if ($found === true) {
+ if ($value === null) {
+ return $i;
+ } else if ($this->tokens[$i]['content'] === $value) {
+ return $i;
+ }
+ }
+
+ if ($local === true) {
+ if (isset($this->tokens[$i]['scope_opener']) === true
+ && $i === $this->tokens[$i]['scope_closer']
+ ) {
+ $i = $this->tokens[$i]['scope_opener'];
+ } else if (isset($this->tokens[$i]['bracket_opener']) === true
+ && $i === $this->tokens[$i]['bracket_closer']
+ ) {
+ $i = $this->tokens[$i]['bracket_opener'];
+ } else if (isset($this->tokens[$i]['parenthesis_opener']) === true
+ && $i === $this->tokens[$i]['parenthesis_closer']
+ ) {
+ $i = $this->tokens[$i]['parenthesis_opener'];
+ } else if ($this->tokens[$i]['code'] === T_SEMICOLON) {
+ break;
+ }
+ }
+ }//end for
+
+ return false;
+
+ }//end findPrevious()
+
+
+ /**
+ * Returns the position of the next specified token(s).
+ *
+ * If a value is specified, the next token of the specified type(s)
+ * containing the specified value will be returned.
+ *
+ * Returns false if no token can be found.
+ *
+ * @param int|array $types The type(s) of tokens to search for.
+ * @param int $start The position to start searching from in the
+ * token stack.
+ * @param int $end The end position to fail if no token is found.
+ * if not specified or null, end will default to
+ * the end of the token stack.
+ * @param bool $exclude If true, find the next token that is NOT of
+ * a type specified in $types.
+ * @param string $value The value that the token(s) must be equal to.
+ * If value is omitted, tokens with any value will
+ * be returned.
+ * @param bool $local If true, tokens outside the current statement
+ * will not be checked. i.e., checking will stop
+ * at the next semi-colon found.
+ *
+ * @return int|bool
+ * @see findPrevious()
+ */
+ public function findNext(
+ $types,
+ $start,
+ $end=null,
+ $exclude=false,
+ $value=null,
+ $local=false
+ ) {
+ $types = (array) $types;
+
+ if ($end === null || $end > $this->numTokens) {
+ $end = $this->numTokens;
+ }
+
+ for ($i = $start; $i < $end; $i++) {
+ $found = (bool) $exclude;
+ foreach ($types as $type) {
+ if ($this->tokens[$i]['code'] === $type) {
+ $found = !$exclude;
+ break;
+ }
+ }
+
+ if ($found === true) {
+ if ($value === null) {
+ return $i;
+ } else if ($this->tokens[$i]['content'] === $value) {
+ return $i;
+ }
+ }
+
+ if ($local === true && $this->tokens[$i]['code'] === T_SEMICOLON) {
+ break;
+ }
+ }//end for
+
+ return false;
+
+ }//end findNext()
+
+
+ /**
+ * Returns the position of the first non-whitespace token in a statement.
+ *
+ * @param int $start The position to start searching from in the token stack.
+ * @param int|array $ignore Token types that should not be considered stop points.
+ *
+ * @return int
+ */
+ public function findStartOfStatement($start, $ignore=null)
+ {
+ $endTokens = Util\Tokens::$blockOpeners;
+
+ $endTokens[T_COLON] = true;
+ $endTokens[T_COMMA] = true;
+ $endTokens[T_DOUBLE_ARROW] = true;
+ $endTokens[T_SEMICOLON] = true;
+ $endTokens[T_OPEN_TAG] = true;
+ $endTokens[T_CLOSE_TAG] = true;
+ $endTokens[T_OPEN_SHORT_ARRAY] = true;
+
+ if ($ignore !== null) {
+ $ignore = (array) $ignore;
+ foreach ($ignore as $code) {
+ if (isset($endTokens[$code]) === true) {
+ unset($endTokens[$code]);
+ }
+ }
+ }
+
+ $lastNotEmpty = $start;
+
+ for ($i = $start; $i >= 0; $i--) {
+ if (isset($endTokens[$this->tokens[$i]['code']]) === true) {
+ // Found the end of the previous statement.
+ return $lastNotEmpty;
+ }
+
+ if (isset($this->tokens[$i]['scope_opener']) === true
+ && $i === $this->tokens[$i]['scope_closer']
+ ) {
+ // Found the end of the previous scope block.
+ return $lastNotEmpty;
+ }
+
+ // Skip nested statements.
+ if (isset($this->tokens[$i]['bracket_opener']) === true
+ && $i === $this->tokens[$i]['bracket_closer']
+ ) {
+ $i = $this->tokens[$i]['bracket_opener'];
+ } else if (isset($this->tokens[$i]['parenthesis_opener']) === true
+ && $i === $this->tokens[$i]['parenthesis_closer']
+ ) {
+ $i = $this->tokens[$i]['parenthesis_opener'];
+ }
+
+ if (isset(Util\Tokens::$emptyTokens[$this->tokens[$i]['code']]) === false) {
+ $lastNotEmpty = $i;
+ }
+ }//end for
+
+ return 0;
+
+ }//end findStartOfStatement()
+
+
+ /**
+ * Returns the position of the last non-whitespace token in a statement.
+ *
+ * @param int $start The position to start searching from in the token stack.
+ * @param int|array $ignore Token types that should not be considered stop points.
+ *
+ * @return int
+ */
+ public function findEndOfStatement($start, $ignore=null)
+ {
+ $endTokens = array(
+ T_COLON => true,
+ T_COMMA => true,
+ T_DOUBLE_ARROW => true,
+ T_SEMICOLON => true,
+ T_CLOSE_PARENTHESIS => true,
+ T_CLOSE_SQUARE_BRACKET => true,
+ T_CLOSE_CURLY_BRACKET => true,
+ T_CLOSE_SHORT_ARRAY => true,
+ T_OPEN_TAG => true,
+ T_CLOSE_TAG => true,
+ );
+
+ if ($ignore !== null) {
+ $ignore = (array) $ignore;
+ foreach ($ignore as $code) {
+ if (isset($endTokens[$code]) === true) {
+ unset($endTokens[$code]);
+ }
+ }
+ }
+
+ $lastNotEmpty = $start;
+
+ for ($i = $start; $i < $this->numTokens; $i++) {
+ if ($i !== $start && isset($endTokens[$this->tokens[$i]['code']]) === true) {
+ // Found the end of the statement.
+ if ($this->tokens[$i]['code'] === T_CLOSE_PARENTHESIS
+ || $this->tokens[$i]['code'] === T_CLOSE_SQUARE_BRACKET
+ || $this->tokens[$i]['code'] === T_CLOSE_CURLY_BRACKET
+ || $this->tokens[$i]['code'] === T_CLOSE_SHORT_ARRAY
+ || $this->tokens[$i]['code'] === T_OPEN_TAG
+ || $this->tokens[$i]['code'] === T_CLOSE_TAG
+ ) {
+ return $lastNotEmpty;
+ }
+
+ return $i;
+ }
+
+ // Skip nested statements.
+ if (isset($this->tokens[$i]['scope_closer']) === true
+ && ($i === $this->tokens[$i]['scope_opener']
+ || $i === $this->tokens[$i]['scope_condition'])
+ ) {
+ $i = $this->tokens[$i]['scope_closer'];
+ } else if (isset($this->tokens[$i]['bracket_closer']) === true
+ && $i === $this->tokens[$i]['bracket_opener']
+ ) {
+ $i = $this->tokens[$i]['bracket_closer'];
+ } else if (isset($this->tokens[$i]['parenthesis_closer']) === true
+ && $i === $this->tokens[$i]['parenthesis_opener']
+ ) {
+ $i = $this->tokens[$i]['parenthesis_closer'];
+ }
+
+ if (isset(Util\Tokens::$emptyTokens[$this->tokens[$i]['code']]) === false) {
+ $lastNotEmpty = $i;
+ }
+ }//end for
+
+ return ($this->numTokens - 1);
+
+ }//end findEndOfStatement()
+
+
+ /**
+ * Returns the position of the first token on a line, matching given type.
+ *
+ * Returns false if no token can be found.
+ *
+ * @param int|array $types The type(s) of tokens to search for.
+ * @param int $start The position to start searching from in the
+ * token stack. The first token matching on
+ * this line before this token will be returned.
+ * @param bool $exclude If true, find the token that is NOT of
+ * the types specified in $types.
+ * @param string $value The value that the token must be equal to.
+ * If value is omitted, tokens with any value will
+ * be returned.
+ *
+ * @return int | bool
+ */
+ public function findFirstOnLine($types, $start, $exclude=false, $value=null)
+ {
+ if (is_array($types) === false) {
+ $types = array($types);
+ }
+
+ $foundToken = false;
+
+ for ($i = $start; $i >= 0; $i--) {
+ if ($this->tokens[$i]['line'] < $this->tokens[$start]['line']) {
+ break;
+ }
+
+ $found = $exclude;
+ foreach ($types as $type) {
+ if ($exclude === false) {
+ if ($this->tokens[$i]['code'] === $type) {
+ $found = true;
+ break;
+ }
+ } else {
+ if ($this->tokens[$i]['code'] === $type) {
+ $found = false;
+ break;
+ }
+ }
+ }
+
+ if ($found === true) {
+ if ($value === null) {
+ $foundToken = $i;
+ } else if ($this->tokens[$i]['content'] === $value) {
+ $foundToken = $i;
+ }
+ }
+ }//end for
+
+ return $foundToken;
+
+ }//end findFirstOnLine()
+
+
+ /**
+ * Determine if the passed token has a condition of one of the passed types.
+ *
+ * @param int $stackPtr The position of the token we are checking.
+ * @param int|array $types The type(s) of tokens to search for.
+ *
+ * @return boolean
+ */
+ public function hasCondition($stackPtr, $types)
+ {
+ // Check for the existence of the token.
+ if (isset($this->tokens[$stackPtr]) === false) {
+ return false;
+ }
+
+ // Make sure the token has conditions.
+ if (isset($this->tokens[$stackPtr]['conditions']) === false) {
+ return false;
+ }
+
+ $types = (array) $types;
+ $conditions = $this->tokens[$stackPtr]['conditions'];
+
+ foreach ($types as $type) {
+ if (in_array($type, $conditions) === true) {
+ // We found a token with the required type.
+ return true;
+ }
+ }
+
+ return false;
+
+ }//end hasCondition()
+
+
+ /**
+ * Return the position of the condition for the passed token.
+ *
+ * Returns FALSE if the token does not have the condition.
+ *
+ * @param int $stackPtr The position of the token we are checking.
+ * @param int $type The type of token to search for.
+ *
+ * @return int
+ */
+ public function getCondition($stackPtr, $type)
+ {
+ // Check for the existence of the token.
+ if (isset($this->tokens[$stackPtr]) === false) {
+ return false;
+ }
+
+ // Make sure the token has conditions.
+ if (isset($this->tokens[$stackPtr]['conditions']) === false) {
+ return false;
+ }
+
+ $conditions = $this->tokens[$stackPtr]['conditions'];
+ foreach ($conditions as $token => $condition) {
+ if ($condition === $type) {
+ return $token;
+ }
+ }
+
+ return false;
+
+ }//end getCondition()
+
+
+ /**
+ * Returns the name of the class that the specified class extends.
+ * (works for classes, anonymous classes and interfaces)
+ *
+ * Returns FALSE on error or if there is no extended class name.
+ *
+ * @param int $stackPtr The stack position of the class.
+ *
+ * @return string|false
+ */
+ public function findExtendedClassName($stackPtr)
+ {
+ // Check for the existence of the token.
+ if (isset($this->tokens[$stackPtr]) === false) {
+ return false;
+ }
+
+ if ($this->tokens[$stackPtr]['code'] !== T_CLASS
+ && $this->tokens[$stackPtr]['code'] !== T_ANON_CLASS
+ && $this->tokens[$stackPtr]['code'] !== T_INTERFACE
+ ) {
+ return false;
+ }
+
+ if (isset($this->tokens[$stackPtr]['scope_closer']) === false) {
+ return false;
+ }
+
+ $classCloserIndex = $this->tokens[$stackPtr]['scope_closer'];
+ $extendsIndex = $this->findNext(T_EXTENDS, $stackPtr, $classCloserIndex);
+ if (false === $extendsIndex) {
+ return false;
+ }
+
+ $find = array(
+ T_NS_SEPARATOR,
+ T_STRING,
+ T_WHITESPACE,
+ );
+
+ $end = $this->findNext($find, ($extendsIndex + 1), $classCloserIndex, true);
+ $name = $this->getTokensAsString(($extendsIndex + 1), ($end - $extendsIndex - 1));
+ $name = trim($name);
+
+ if ($name === '') {
+ return false;
+ }
+
+ return $name;
+
+ }//end findExtendedClassName()
+
+
+ /**
+ * Returns the names of the interfaces that the specified class implements.
+ *
+ * Returns FALSE on error or if there are no implemented interface names.
+ *
+ * @param int $stackPtr The stack position of the class.
+ *
+ * @return array|false
+ */
+ public function findImplementedInterfaceNames($stackPtr)
+ {
+ // Check for the existence of the token.
+ if (isset($this->tokens[$stackPtr]) === false) {
+ return false;
+ }
+
+ if ($this->tokens[$stackPtr]['code'] !== T_CLASS
+ && $this->tokens[$stackPtr]['code'] !== T_ANON_CLASS
+ ) {
+ return false;
+ }
+
+ if (isset($this->tokens[$stackPtr]['scope_closer']) === false) {
+ return false;
+ }
+
+ $classOpenerIndex = $this->tokens[$stackPtr]['scope_opener'];
+ $implementsIndex = $this->findNext(T_IMPLEMENTS, $stackPtr, $classOpenerIndex);
+ if ($implementsIndex === false) {
+ return false;
+ }
+
+ $find = array(
+ T_NS_SEPARATOR,
+ T_STRING,
+ T_WHITESPACE,
+ T_COMMA,
+ );
+
+ $end = $this->findNext($find, ($implementsIndex + 1), ($classOpenerIndex + 1), true);
+ $name = $this->getTokensAsString(($implementsIndex + 1), ($end - $implementsIndex - 1));
+ $name = trim($name);
+
+ if ($name === '') {
+ return false;
+ } else {
+ $names = explode(',', $name);
+ $names = array_map('trim', $names);
+ return $names;
+ }
+
+ }//end findImplementedInterfaceNames()
+
+
+}//end class
diff --git a/vendor/squizlabs/php_codesniffer/src/Files/FileList.php b/vendor/squizlabs/php_codesniffer/src/Files/FileList.php
new file mode 100644
index 0000000..c6b7d2b
--- /dev/null
+++ b/vendor/squizlabs/php_codesniffer/src/Files/FileList.php
@@ -0,0 +1,246 @@
+
+ * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
+ */
+
+namespace PHP_CodeSniffer\Files;
+
+use PHP_CodeSniffer\Util;
+use PHP_CodeSniffer\Ruleset;
+use PHP_CodeSniffer\Config;
+use PHP_CodeSniffer\Exceptions\DeepExitException;
+
+class FileList implements \Iterator, \Countable
+{
+
+ /**
+ * A list of file paths that are included in the list.
+ *
+ * @var array
+ */
+ private $files = array();
+
+ /**
+ * The number of files in the list.
+ *
+ * @var integer
+ */
+ private $numFiles = 0;
+
+ /**
+ * The config data for the run.
+ *
+ * @var \PHP_CodeSniffer\Config
+ */
+ public $config = null;
+
+ /**
+ * The ruleset used for the run.
+ *
+ * @var \PHP_CodeSniffer\Ruleset
+ */
+ public $ruleset = null;
+
+ /**
+ * An array of patterns to use for skipping files.
+ *
+ * @var array
+ */
+ protected $ignorePatterns = array();
+
+
+ /**
+ * Constructs a file list and loads in an array of file paths to process.
+ *
+ * @param \PHP_CodeSniffer\Config $config The config data for the run.
+ * @param \PHP_CodeSniffer\Ruleset $ruleset The ruleset used for the run.
+ *
+ * @return void
+ */
+ public function __construct(Config $config, Ruleset $ruleset)
+ {
+ $this->ruleset = $ruleset;
+ $this->config = $config;
+
+ $paths = $config->files;
+ foreach ($paths as $path) {
+ $isPharFile = Util\Common::isPharFile($path);
+ if (is_dir($path) === true || $isPharFile === true) {
+ if ($isPharFile === true) {
+ $path = 'phar://'.$path;
+ }
+
+ $filterClass = $this->getFilterClass();
+
+ $di = new \RecursiveDirectoryIterator($path, (\RecursiveDirectoryIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS));
+ $filter = new $filterClass($di, $path, $config, $ruleset);
+ $iterator = new \RecursiveIteratorIterator($filter);
+
+ foreach ($iterator as $file) {
+ $this->files[$file->getPathname()] = null;
+ $this->numFiles++;
+ }
+ } else {
+ $this->addFile($path);
+ }//end if
+ }//end foreach
+
+ reset($this->files);
+
+ }//end __construct()
+
+
+ /**
+ * Add a file to the list.
+ *
+ * If a file object has already been created, it can be passed here.
+ * If it is left NULL, it will be created when accessed.
+ *
+ * @param string $path The path to the file being added.
+ * @param \PHP_CodeSniffer\Files\File $file The file being added.
+ *
+ * @return void
+ */
+ public function addFile($path, $file=null)
+ {
+ // No filtering is done for STDIN when the filename
+ // has not been specified.
+ if ($path === 'STDIN') {
+ $this->files[$path] = $file;
+ $this->numFiles++;
+ return;
+ }
+
+ $filterClass = $this->getFilterClass();
+
+ $di = new \RecursiveArrayIterator(array($path));
+ $filter = new $filterClass($di, $path, $this->config, $this->ruleset);
+ $iterator = new \RecursiveIteratorIterator($filter);
+
+ foreach ($iterator as $path) {
+ $this->files[$path] = $file;
+ $this->numFiles++;
+ }
+
+ }//end addFile()
+
+
+ /**
+ * Get the class name of the filter being used for the run.
+ *
+ * @return string
+ */
+ private function getFilterClass()
+ {
+ $filterType = $this->config->filter;
+
+ if ($filterType === null) {
+ $filterClass = '\PHP_CodeSniffer\Filters\Filter';
+ } else {
+ if (strpos($filterType, '.') !== false) {
+ // This is a path to a custom filter class.
+ $filename = realpath($filterType);
+ if ($filename === false) {
+ $error = "ERROR: Custom filter \"$filterType\" not found".PHP_EOL;
+ throw new DeepExitException($error, 3);
+ }
+
+ $filterClass = \PHP_CodeSniffer\Autoload::loadFile($filename);
+ } else {
+ $filterClass = '\PHP_CodeSniffer\Filters\\'.$filterType;
+ }
+ }
+
+ return $filterClass;
+
+ }//end getFilterClass()
+
+
+ /**
+ * Rewind the iterator to the first file.
+ *
+ * @return void
+ */
+ function rewind()
+ {
+ reset($this->files);
+
+ }//end rewind()
+
+
+ /**
+ * Get the file that is currently being processed.
+ *
+ * @return \PHP_CodeSniffer\Files\File
+ */
+ function current()
+ {
+ $path = key($this->files);
+ if ($this->files[$path] === null) {
+ $this->files[$path] = new LocalFile($path, $this->ruleset, $this->config);
+ }
+
+ return $this->files[$path];
+
+ }//end current()
+
+
+ /**
+ * Return the file path of the current file being processed.
+ *
+ * @return void
+ */
+ function key()
+ {
+ return key($this->files);
+
+ }//end key()
+
+
+ /**
+ * Move forward to the next file.
+ *
+ * @return void
+ */
+ function next()
+ {
+ next($this->files);
+
+ }//end next()
+
+
+ /**
+ * Checks if current position is valid.
+ *
+ * @return boolean
+ */
+ function valid()
+ {
+ if (current($this->files) === false) {
+ return false;
+ }
+
+ return true;
+
+ }//end valid()
+
+
+ /**
+ * Return the number of files in the list.
+ *
+ * @return integer
+ */
+ function count()
+ {
+ return $this->numFiles;
+
+ }//end count()
+
+
+}//end class
diff --git a/vendor/squizlabs/php_codesniffer/src/Files/LocalFile.php b/vendor/squizlabs/php_codesniffer/src/Files/LocalFile.php
new file mode 100644
index 0000000..00ee2d6
--- /dev/null
+++ b/vendor/squizlabs/php_codesniffer/src/Files/LocalFile.php
@@ -0,0 +1,210 @@
+
+ * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
+ */
+
+namespace PHP_CodeSniffer\Files;
+
+use PHP_CodeSniffer\Ruleset;
+use PHP_CodeSniffer\Config;
+use PHP_CodeSniffer\Util\Cache;
+
+class LocalFile extends File
+{
+
+
+ /**
+ * Creates a LocalFile object and sets the content.
+ *
+ * @param string $path The absolute path to the file.
+ * @param \PHP_CodeSniffer\Ruleset $ruleset The ruleset used for the run.
+ * @param \PHP_CodeSniffer\Config $config The config data for the run.
+ *
+ * @return void
+ */
+ public function __construct($path, Ruleset $ruleset, Config $config)
+ {
+ $this->path = trim($path);
+ if (is_readable($this->path) === false) {
+ parent::__construct($this->path, $ruleset, $config);
+ $error = 'Error opening file; file no longer exists or you do not have access to read the file';
+ $this->addMessage(true, $error, 1, 1, 'Internal.LocalFile', array(), 5, false);
+ $this->ignored = true;
+ return;
+ }
+
+ // Before we go and spend time tokenizing this file, just check
+ // to see if there is a tag up top to indicate that the whole
+ // file should be ignored. It must be on one of the first two lines.
+ if ($config->annotations === true) {
+ $handle = fopen($this->path, 'r');
+ if ($handle !== false) {
+ $firstContent = fgets($handle);
+ $firstContent .= fgets($handle);
+ fclose($handle);
+
+ if (strpos($firstContent, '@codingStandardsIgnoreFile') !== false) {
+ // We are ignoring the whole file.
+ $this->ignored = true;
+ return;
+ }
+ }
+ }
+
+ $this->reloadContent();
+
+ return parent::__construct($this->path, $ruleset, $config);
+
+ }//end __construct()
+
+
+ /**
+ * Loads the latest version of the file's content from the file system.
+ *
+ * @return void
+ */
+ function reloadContent()
+ {
+ $this->setContent(file_get_contents($this->path));
+
+ }//end reloadContent()
+
+
+ /**
+ * Processes the file.
+ *
+ * @return void
+ */
+ public function process()
+ {
+ if ($this->ignored === true) {
+ return;
+ }
+
+ if ($this->configCache['cache'] === false) {
+ return parent::process();
+ }
+
+ $hash = md5_file($this->path);
+ $cache = Cache::get($this->path);
+ if ($cache !== false && $cache['hash'] === $hash) {
+ // We can't filter metrics, so just load all of them.
+ $this->metrics = $cache['metrics'];
+
+ if ($this->configCache['recordErrors'] === true) {
+ // Replay the cached errors and warnings to filter out the ones
+ // we don't need for this specific run.
+ $this->configCache['cache'] = false;
+ $this->replayErrors($cache['errors'], $cache['warnings']);
+ $this->configCache['cache'] = true;
+ } else {
+ $this->errorCount = $cache['errorCount'];
+ $this->warningCount = $cache['warningCount'];
+ $this->fixableCount = $cache['fixableCount'];
+ }
+
+ if (PHP_CODESNIFFER_VERBOSITY > 0
+ || (PHP_CODESNIFFER_CBF === true && empty($this->config->files) === false)
+ ) {
+ echo "[loaded from cache]... ";
+ }
+
+ $this->numTokens = $cache['numTokens'];
+ $this->fromCache = true;
+ return;
+ }//end if
+
+ if (PHP_CODESNIFFER_VERBOSITY > 1) {
+ echo PHP_EOL;
+ }
+
+ parent::process();
+
+ $cache = array(
+ 'hash' => $hash,
+ 'errors' => $this->errors,
+ 'warnings' => $this->warnings,
+ 'metrics' => $this->metrics,
+ 'errorCount' => $this->errorCount,
+ 'warningCount' => $this->warningCount,
+ 'fixableCount' => $this->fixableCount,
+ 'numTokens' => $this->numTokens,
+ );
+
+ Cache::set($this->path, $cache);
+
+ // During caching, we don't filter out errors in any way, so
+ // we need to do that manually now by replaying them.
+ if ($this->configCache['recordErrors'] === true) {
+ $this->configCache['cache'] = false;
+ $this->replayErrors($this->errors, $this->warnings);
+ $this->configCache['cache'] = true;
+ }
+
+ }//end process()
+
+
+ /**
+ * Clears and replays error and warnings for the file.
+ *
+ * Replaying errors and warnings allows for filtering rules to be changed
+ * and then errors and warnings to be reapplied with the new rules. This is
+ * particularly useful while caching.
+ *
+ * @param array $errors The list of errors to replay.
+ * @param array $warnings The list of warnings to replay.
+ *
+ * @return void
+ */
+ private function replayErrors($errors, $warnings)
+ {
+ $this->errors = array();
+ $this->warnings = array();
+ $this->errorCount = 0;
+ $this->warningCount = 0;
+ $this->fixableCount = 0;
+
+ foreach ($errors as $line => $lineErrors) {
+ foreach ($lineErrors as $column => $colErrors) {
+ foreach ($colErrors as $error) {
+ $this->activeListener = $error['listener'];
+ $this->addMessage(
+ true,
+ $error['message'],
+ $line,
+ $column,
+ $error['source'],
+ array(),
+ $error['severity'],
+ $error['fixable']
+ );
+ }
+ }
+ }
+
+ foreach ($warnings as $line => $lineErrors) {
+ foreach ($lineErrors as $column => $colErrors) {
+ foreach ($colErrors as $error) {
+ $this->activeListener = $error['listener'];
+ $this->addMessage(
+ false,
+ $error['message'],
+ $line,
+ $column,
+ $error['source'],
+ array(),
+ $error['severity'],
+ $error['fixable']
+ );
+ }
+ }
+ }
+
+ }//end replayErrors()
+
+
+}//end class
diff --git a/vendor/squizlabs/php_codesniffer/src/Filters/ExactMatch.php b/vendor/squizlabs/php_codesniffer/src/Filters/ExactMatch.php
new file mode 100644
index 0000000..13af8ff
--- /dev/null
+++ b/vendor/squizlabs/php_codesniffer/src/Filters/ExactMatch.php
@@ -0,0 +1,108 @@
+
+ * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
+ */
+
+namespace PHP_CodeSniffer\Filters;
+
+use PHP_CodeSniffer\Util;
+
+abstract class ExactMatch extends Filter
+{
+
+ /**
+ * A list of files to exclude.
+ *
+ * @var array
+ */
+ private $blacklist = null;
+
+ /**
+ * A list of files to include.
+ *
+ * If the whitelist is empty, only files in the blacklist will be excluded.
+ *
+ * @var array
+ */
+ private $whitelist = null;
+
+
+ /**
+ * Check whether the current element of the iterator is acceptable.
+ *
+ * If a file is both blacklisted and whitelisted, it will be deemed unacceptable.
+ *
+ * @return bool
+ */
+ public function accept()
+ {
+ if (parent::accept() === false) {
+ return false;
+ }
+
+ if ($this->blacklist === null) {
+ $this->blacklist = $this->getblacklist();
+ }
+
+ if ($this->whitelist === null) {
+ $this->whitelist = $this->getwhitelist();
+ }
+
+ $filePath = Util\Common::realpath($this->current());
+
+ // If file is both blacklisted and whitelisted, the blacklist takes precedence.
+ if (isset($this->blacklist[$filePath]) === true) {
+ return false;
+ }
+
+ if (empty($this->whitelist) === true && empty($this->blacklist) === false) {
+ // We are only checking a blacklist, so everything else should be whitelisted.
+ return true;
+ }
+
+ return isset($this->whitelist[$filePath]);
+
+ }//end accept()
+
+
+ /**
+ * Returns an iterator for the current entry.
+ *
+ * Ensures that the blacklist and whitelist are preserved so they don't have
+ * to be generated each time.
+ *
+ * @return \RecursiveIterator
+ */
+ public function getChildren()
+ {
+ $children = parent::getChildren();
+ $children->blacklist = $this->blacklist;
+ $children->whitelist = $this->whitelist;
+ return $children;
+
+ }//end getChildren()
+
+
+ /**
+ * Get a list of blacklisted file paths.
+ *
+ * @return array
+ */
+ abstract protected function getBlacklist();
+
+
+ /**
+ * Get a list of whitelisted file paths.
+ *
+ * @return array
+ */
+ abstract protected function getWhitelist();
+
+
+}//end class
diff --git a/vendor/squizlabs/php_codesniffer/src/Filters/Filter.php b/vendor/squizlabs/php_codesniffer/src/Filters/Filter.php
new file mode 100644
index 0000000..61581e1
--- /dev/null
+++ b/vendor/squizlabs/php_codesniffer/src/Filters/Filter.php
@@ -0,0 +1,245 @@
+
+ * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
+ */
+
+namespace PHP_CodeSniffer\Filters;
+
+use PHP_CodeSniffer\Util;
+use PHP_CodeSniffer\Ruleset;
+use PHP_CodeSniffer\Config;
+
+class Filter extends \RecursiveFilterIterator
+{
+ /**
+ * The top-level path we are filtering.
+ *
+ * @var string
+ */
+ protected $basedir = null;
+
+ /**
+ * The config data for the run.
+ *
+ * @var \PHP_CodeSniffer\Config
+ */
+ protected $config = null;
+
+ /**
+ * The ruleset used for the run.
+ *
+ * @var \PHP_CodeSniffer\Ruleset
+ */
+ protected $ruleset = null;
+
+ /**
+ * A list of ignore patterns that apply to directories only.
+ *
+ * @var array
+ */
+ protected $ignoreDirPatterns = null;
+
+ /**
+ * A list of ignore patterns that apply to files only.
+ *
+ * @var array
+ */
+ protected $ignoreFilePatterns = null;
+
+
+ /**
+ * Constructs a filter.
+ *
+ * @param \RecursiveIterator $iterator The iterator we are using to get file paths.
+ * @param string $basedir The top-level path we are filtering.
+ * @param \PHP_CodeSniffer\Config $config The config data for the run.
+ * @param \PHP_CodeSniffer\Ruleset $ruleset The ruleset used for the run.
+ *
+ * @return void
+ */
+ public function __construct($iterator, $basedir, Config $config, Ruleset $ruleset)
+ {
+ parent::__construct($iterator);
+ $this->basedir = $basedir;
+ $this->config = $config;
+ $this->ruleset = $ruleset;
+
+ }//end __construct()
+
+
+ /**
+ * Check whether the current element of the iterator is acceptable.
+ *
+ * Files are checked for allowed extensions and ignore patterns.
+ * Directories are checked for ignore patterns only.
+ *
+ * @return bool
+ */
+ public function accept()
+ {
+ $filePath = Util\Common::realpath($this->current());
+ if ($filePath === false) {
+ return false;
+ }
+
+ if (is_dir($filePath) === true) {
+ if ($this->config->local === true) {
+ return false;
+ }
+ } else if ($this->shouldProcessFile($filePath) === false) {
+ return false;
+ }
+
+ if ($this->shouldIgnorePath($filePath) === true) {
+ return false;
+ }
+
+ return true;
+
+ }//end accept()
+
+
+ /**
+ * Returns an iterator for the current entry.
+ *
+ * Ensures that the ignore patterns are preserved so they don't have
+ * to be generated each time.
+ *
+ * @return \RecursiveIterator
+ */
+ public function getChildren()
+ {
+ $children = new static(
+ new \RecursiveDirectoryIterator($this->current(), (\RecursiveDirectoryIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS)),
+ $this->basedir,
+ $this->config,
+ $this->ruleset
+ );
+
+ // Set the ignore patterns so we don't have to generate them again.
+ $children->ignoreDirPatterns = $this->ignoreDirPatterns;
+ $children->ignoreFilePatterns = $this->ignoreFilePatterns;
+ return $children;
+
+ }//end getChildren()
+
+
+ /**
+ * Checks filtering rules to see if a file should be checked.
+ *
+ * Checks both file extension filters and path ignore filters.
+ *
+ * @param string $path The path to the file being checked.
+ *
+ * @return bool
+ */
+ protected function shouldProcessFile($path)
+ {
+ // Check that the file's extension is one we are checking.
+ // We are strict about checking the extension and we don't
+ // let files through with no extension or that start with a dot.
+ $fileName = basename($path);
+ $fileParts = explode('.', $fileName);
+ if ($fileParts[0] === $fileName || $fileParts[0] === '') {
+ return false;
+ }
+
+ // Checking multi-part file extensions, so need to create a
+ // complete extension list and make sure one is allowed.
+ $extensions = array();
+ array_shift($fileParts);
+ foreach ($fileParts as $part) {
+ $extensions[implode('.', $fileParts)] = 1;
+ array_shift($fileParts);
+ }
+
+ $matches = array_intersect_key($extensions, $this->config->extensions);
+ if (empty($matches) === true) {
+ return false;
+ }
+
+ return true;
+
+ }//end shouldProcessFile()
+
+
+ /**
+ * Checks filtering rules to see if a path should be ignored.
+ *
+ * @param string $path The path to the file or directory being checked.
+ *
+ * @return bool
+ */
+ protected function shouldIgnorePath($path)
+ {
+ if ($this->ignoreFilePatterns === null) {
+ $this->ignoreDirPatterns = array();
+ $this->ignoreFilePatterns = array();
+
+ $ignorePatterns = array_merge($this->config->ignored, $this->ruleset->getIgnorePatterns());
+ foreach ($ignorePatterns as $pattern => $type) {
+ // If the ignore pattern ends with /* then it is ignoring an entire directory.
+ if (substr($pattern, -2) === '/*') {
+ $this->ignoreDirPatterns[substr($pattern, 0, -2)] = $type;
+ } else {
+ $this->ignoreFilePatterns[$pattern] = $type;
+ }
+ }
+ }
+
+ $relativePath = $path;
+ if (strpos($path, $this->basedir) === 0) {
+ // The +1 cuts off the directory separator as well.
+ $relativePath = substr($path, (strlen($this->basedir) + 1));
+ }
+
+ if (is_dir($path) === true) {
+ $ignorePatterns = $this->ignoreDirPatterns;
+ } else {
+ $ignorePatterns = $this->ignoreFilePatterns;
+ }
+
+ foreach ($ignorePatterns as $pattern => $type) {
+ // Maintains backwards compatibility in case the ignore pattern does
+ // not have a relative/absolute value.
+ if (is_int($pattern) === true) {
+ $pattern = $type;
+ $type = 'absolute';
+ }
+
+ $replacements = array(
+ '\\,' => ',',
+ '*' => '.*',
+ );
+
+ // We assume a / directory separator, as do the exclude rules
+ // most developers write, so we need a special case for any system
+ // that is different.
+ if (DIRECTORY_SEPARATOR === '\\') {
+ $replacements['/'] = '\\\\';
+ }
+
+ $pattern = strtr($pattern, $replacements);
+
+ if ($type === 'relative') {
+ $testPath = $relativePath;
+ } else {
+ $testPath = $path;
+ }
+
+ $pattern = '`'.$pattern.'`i';
+ if (preg_match($pattern, $testPath) === 1) {
+ return true;
+ }
+ }//end foreach
+
+ return false;
+
+ }//end shouldIgnorePath()
+
+
+}//end class
diff --git a/vendor/squizlabs/php_codesniffer/src/Filters/GitModified.php b/vendor/squizlabs/php_codesniffer/src/Filters/GitModified.php
new file mode 100644
index 0000000..86512e2
--- /dev/null
+++ b/vendor/squizlabs/php_codesniffer/src/Filters/GitModified.php
@@ -0,0 +1,61 @@
+
+ * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
+ */
+
+namespace PHP_CodeSniffer\Filters;
+
+use PHP_CodeSniffer\Util;
+
+class GitModified extends ExactMatch
+{
+
+
+ /**
+ * Get a list of blacklisted file paths.
+ *
+ * @return array
+ */
+ protected function getBlacklist()
+ {
+ return array();
+
+ }//end getBlacklist()
+
+
+ /**
+ * Get a list of whitelisted file paths.
+ *
+ * @return array
+ */
+ protected function getWhitelist()
+ {
+ $modified = array();
+
+ $cmd = 'git ls-files -o -m --exclude-standard -- '.escapeshellarg($this->basedir);
+ $output = array();
+ exec($cmd, $output);
+
+ $basedir = $this->basedir;
+ if (is_dir($basedir) === false) {
+ $basedir = dirname($basedir);
+ }
+
+ foreach ($output as $path) {
+ $path = Util\Common::realpath($path);
+ do {
+ $modified[$path] = true;
+ $path = dirname($path);
+ } while ($path !== $basedir);
+ }
+
+ return $modified;
+
+ }//end getWhitelist()
+
+
+}//end class
diff --git a/vendor/squizlabs/php_codesniffer/src/Fixer.php b/vendor/squizlabs/php_codesniffer/src/Fixer.php
new file mode 100644
index 0000000..e16dc5f
--- /dev/null
+++ b/vendor/squizlabs/php_codesniffer/src/Fixer.php
@@ -0,0 +1,728 @@
+
+ * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
+ * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
+ */
+
+namespace PHP_CodeSniffer;
+
+use PHP_CodeSniffer\Files\File;
+use PHP_CodeSniffer\Util\Common;
+
+class Fixer
+{
+
+ /**
+ * Is the fixer enabled and fixing a file?
+ *
+ * Sniffs should check this value to ensure they are not
+ * doing extra processing to prepare for a fix when fixing is
+ * not required.
+ *
+ * @var boolean
+ */
+ public $enabled = false;
+
+ /**
+ * The number of times we have looped over a file.
+ *
+ * @var integer
+ */
+ public $loops = 0;
+
+ /**
+ * The file being fixed.
+ *
+ * @var \PHP_CodeSniffer\Files\File
+ */
+ private $currentFile = null;
+
+ /**
+ * The list of tokens that make up the file contents.
+ *
+ * This is a simplified list which just contains the token content and nothing
+ * else. This is the array that is updated as fixes are made, not the file's
+ * token array. Imploding this array will give you the file content back.
+ *
+ * @var array$content
".PHP_EOL; + + }//end printTextBlock() + + + /** + * Print a code comparison block found in a standard. + * + * @param \DOMNode $node The DOMNode object for the code comparison block. + * + * @return void + */ + protected function printCodeComparisonBlock(\DOMNode $node) + { + $codeBlocks = $node->getElementsByTagName('code'); + + $firstTitle = $codeBlocks->item(0)->getAttribute('title'); + $first = trim($codeBlocks->item(0)->nodeValue); + $first = str_replace('', $first); + $first = str_replace(' ', ' ', $first); + $first = str_replace('', '', $first); + $first = str_replace('', '', $first); + + $secondTitle = $codeBlocks->item(1)->getAttribute('title'); + $second = trim($codeBlocks->item(1)->nodeValue); + $second = str_replace('', $second); + $second = str_replace(' ', ' ', $second); + $second = str_replace('', '', $second); + $second = str_replace('', '', $second); + + echo '$firstTitle | ".PHP_EOL; + echo "$secondTitle | ".PHP_EOL; + echo '
$first | ".PHP_EOL; + echo "$second | ".PHP_EOL; + echo '
$firstTitle | ".PHP_EOL; + echo "$secondTitle | ".PHP_EOL; + echo '
---|---|
'.PHP_EOL.PHP_EOL; + echo " $first".PHP_EOL.PHP_EOL; + echo ' | '.PHP_EOL; + echo ''.PHP_EOL.PHP_EOL; + echo " $second".PHP_EOL.PHP_EOL; + echo ' | '.PHP_EOL; + echo '
+ * array(
+ * T_WHITESPACE => 0, // 0 is the position where the T_WHITESPACE token
+ * // should occur in the pattern.
+ * );
+ *
+ *
+ * @param array $pattern The parsed pattern to find the acquire the token
+ * types from.
+ *
+ * @return array
+ * return array(
+ * T_WHITESPACE,
+ * T_DOC_COMMENT,
+ * T_COMMENT,
+ * );
+ *
+ *
+ * @return int[]
+ * @see Tokens.php
+ */
+ public function register();
+
+
+ /**
+ * Called when one of the token types that this sniff is listening for
+ * is found.
+ *
+ * The stackPtr variable indicates where in the stack the token was found.
+ * A sniff can acquire information this token, along with all the other
+ * tokens within the stack by first acquiring the token stack:
+ *
+ *
+ * $tokens = $phpcsFile->getTokens();
+ * echo 'Encountered a '.$tokens[$stackPtr]['type'].' token';
+ * echo 'token information: ';
+ * print_r($tokens[$stackPtr]);
+ *
+ *
+ * If the sniff discovers an anomaly in the code, they can raise an error
+ * by calling addError() on the \PHP_CodeSniffer\Files\File object, specifying an error
+ * message and the position of the offending token:
+ *
+ *
+ * $phpcsFile->addError('Encountered an error', $stackPtr);
+ *
+ *
+ * @param \PHP_CodeSniffer\Files\File $phpcsFile The PHP_CodeSniffer file where the
+ * token was found.
+ * @param int $stackPtr The position in the PHP_CodeSniffer
+ * file's token stack where the token
+ * was found.
+ *
+ * @return void|int Optionally returns a stack pointer. The sniff will not be
+ * called again on the current file until the returned stack
+ * pointer is reached. Return (count($tokens) + 1) to skip
+ * the rest of the file.
+ */
+ public function process(File $phpcsFile, $stackPtr);
+
+
+}//end interface
diff --git a/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Classes/DuplicateClassNameStandard.xml b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Classes/DuplicateClassNameStandard.xml
new file mode 100644
index 0000000..4b0ec96
--- /dev/null
+++ b/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Classes/DuplicateClassNameStandard.xml
@@ -0,0 +1,27 @@
+
+ Foo
+{
+}
+ ]]>
+
+
+ Foo
+{
+}
+
+class Foo
+{
+}
+ ]]>
+
+
+ {
+}
+ ]]>
+
+
+ {
+}
+ ]]>
+
+
+ // Start of class.
+}
+ ]]>
+
+
+ $test === 'abc') {
+ // Code.
+}
+ ]]>
+
+
+ $test = 'abc') {
+ // Code.
+}
+ ]]>
+
+
+
+
+
+ // do nothing
+}
+ ]]>
+
+
+ $i = 0; $i < 10; $i++) {
+ echo "{$i}\n";
+}
+ ]]>
+
+
+ ;$test;) {
+ $test = doSomething();
+}
+ ]]>
+
+
+ $end = count($foo);
+for ($i = 0; $i < $end; $i++) {
+ echo $foo[$i]."\n";
+}
+ ]]>
+
+
+ count($foo); $i++) {
+ echo $foo[$i]."\n";
+}
+ ]]>
+
+
+ $i++) {
+ for ($j = 0; $j < 10; $j++) {
+ }
+}
+ ]]>
+
+
+ $i++) {
+ for ($j = 0; $j < 10; $i++) {
+ }
+}
+ ]]>
+
+
+ $test) {
+ $var = 1;
+}
+ ]]>
+
+
+ true) {
+ $var = 1;
+}
+ ]]>
+
+
+ $test) {
+ $var = 1;
+}
+ ]]>
+
+
+ false) {
+ $var = 1;
+}
+ ]]>
+
+
+
+
+
+ final function bar()
+ {
+ }
+}
+ ]]>
+
+
+ $a + $b + $c;
+}
+ ]]>
+
+
+ $a + $b;
+}
+ ]]>
+
+
+ $this->doSomethingElse();
+ }
+}
+ ]]>
+
+
+ parent::bar();
+ }
+}
+ ]]>
+
+
+ Handle strange case
+if ($test) {
+ $var = 1;
+}
+ ]]>
+
+
+ FIXME: This needs to be fixed!
+if ($test) {
+ $var = 1;
+}
+ ]]>
+
+
+ Handle strange case
+if ($test) {
+ $var = 1;
+}
+ ]]>
+
+
+ TODO: This needs to be fixed!
+if ($test) {
+ $var = 1;
+}
+ ]]>
+
+
+ {
+ $var = 1;
+}
+ ]]>
+
+
+
+
+
+ %; }
+ ]]>
+
+
+ %; }
+ ]]>
+
+
+ ];
+ ]]>
+
+
+ ,];
+ ]]>
+
+
+ var foo = 5;
+ ]]>
+
+
+ foo = 5;
+ ]]>
+
+
+
+
+
+ some string here
+
+
+
+ class Foo
+{
+}
+ ]]>
+
+
+ class Foo
+{
+}
+
+class Bar
+{
+}
+ ]]>
+
+
+ interface Foo
+{
+}
+ ]]>
+
+
+ interface Foo
+{
+}
+
+interface Bar
+{
+}
+ ]]>
+
+
+
+
+
+
+
+
+ = (1 + 2);
+$veryLongVarName = 'string';
+$var = foo($bar, $baz, $quux);
+ ]]>
+
+
+ = (1 + 2);
+$veryLongVarName = 'string';
+$var = foo($bar, $baz, $quux);
+ ]]>
+
+
+ += 1;
+$veryLongVarName = 1;
+ ]]>
+
+
+ += 1;
+$veryLongVarName = 1;
+ ]]>
+
+
+ = 1;
+$veryLongVarName -= 1;
+ ]]>
+
+
+ = 1;
+$veryLongVarName -= 1;
+ ]]>
+
+
+
+
+
+ 1;
+ ]]>
+
+
+ 1;
+ ]]>
+
+
+ 1;
+ ]]>
+
+
+ &$bar)
+{
+ $bar++;
+}
+
+$baz = 1;
+foo($baz);
+ ]]>
+
+
+ &$baz);
+ ]]>
+
+
+ $baz)
+{
+}
+ ]]>
+
+
+ $baz)
+{
+}
+ ]]>
+
+
+ = true)
+{
+}
+ ]]>
+
+
+ =true)
+{
+}
+ ]]>
+
+
+ {
+ ...
+}
+ ]]>
+
+
+ {
+ ...
+}
+ ]]>
+
+
+ {
+ ...
+}
+ ]]>
+
+
+ {
+ ...
+}
+ ]]>
+
+
+ doSomething()
+{
+}
+ ]]>
+
+
+ do_something()
+{
+}
+ ]]>
+
+
+ __construct()
+ {
+ }
+}
+ ]]>
+
+
+ Foo()
+ {
+ }
+}
+ ]]>
+
+
+ FOO_CONSTANT', 'foo');
+
+class FooClass
+{
+ const FOO_CONSTANT = 'foo';
+}
+ ]]>
+
+
+ Foo_Constant', 'foo');
+
+class FooClass
+{
+ const foo_constant = 'foo';
+}
+ ]]>
+
+
+
+
+
+ Beginning content
+
+
+
+
+echo 'Foo';
+?>
+ ]]>
+
+
+
+echo 'Foo';
+ ]]>
+
+
+ explode('a', $bar);
+ ]]>
+
+
+ split('a', $bar);
+ ]]>
+
+
+ count($bar);
+ ]]>
+
+
+ sizeof($bar);
+ ]]>
+
+
+ false || $var === null) {
+ $var = true;
+}
+ ]]>
+
+
+ FALSE || $var === NULL) {
+ $var = TRUE;
+}
+ ]]>
+
+
+ array();
+ ]]>
+
+
+ Array();
+ ]]>
+
+
+ isset($foo) && $foo) {
+ echo "Hello\n";
+}
+ ]]>
+
+
+ @$foo) {
+ echo "Hello\n";
+}
+ ]]>
+
+
+ PHP_SAPI === 'cli') {
+ echo "Hello, CLI user.";
+}
+ ]]>
+
+
+ php_sapi_name() === 'cli') {
+ echo "Hello, CLI user.";
+}
+ ]]>
+
+
+ FALSE || $var === NULL) {
+ $var = TRUE;
+}
+ ]]>
+
+
+ false || $var === null) {
+ $var = true;
+}
+ ]]>
+
+
+
+
+
+
+
+
+ $var = 1;
+}
+ ]]>
+
+
+ $var = 1;
+}
+ ]]>
+
+
+ * class Foo
+ * {
+ * public function close()
+ * {
+ * if (true)
+ * {
+ * // ...
+ * }
+ * }
+ * }
+ *
+ *
+ * @author Manuel Pichler some html here
+ + * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Standards\Generic\Tests\Classes; + +use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; + +class DuplicateClassNameUnitTest extends AbstractSniffUnitTest +{ + + + /** + * Returns the lines where errors should occur. + * + * The key of the array should represent the line number and the value + * should represent the number of errors that should occur on that line. + * + * @return array",$s.";\n"; + else { + $ok = $this->connDest->Execute($s); + if (!$ok) + if ($this->neverAbort) $ret = false; + else return false; + } + +if ($bar) + if ($foo) echo 'hi'; // lol + +if ($level == 'district') + \DB::update(<<
",$s.";\n"; + } else { + $ok = $this->connDest->Execute($s); + if (!$ok) { + if ($this->neverAbort) { $ret = false; + } else { return false; + } + } + } +} + +if ($bar) { + if ($foo) { echo 'hi'; // lol + } +} + +if ($level == 'district') { + \DB::update(<<
Some text <% echo $var; %> and some more text
+<%= $var . ' and some more text to make sure the snippet works'; %> +Some text <%= $var %> and some more text
+Some text and some more text
+ +Some text and some more text
++ + +validate()) { + $safe = $form->getSubmitValues(); +} +?> ++open(); // error here + } + + public function open() + { + // Some inline stuff that shouldn't error + if (TRUE) echo 'hello'; + foreach ($tokens as $token) echo $token; + } + + /** + * This is a comment 1. + * This is a comment 2. + * This is a comment 3. + * This is a comment 4. + */ + public function close() + { + // All ok. + if (TRUE) { + if (TRUE) { + } else if (FALSE) { + foreach ($tokens as $token) { + switch ($token) { + case '1': + case '2': + if (true) { + if (false) { + if (false) { + if (false) { + echo 'hello'; + } + } + } + } + break; + case '5': + break; + } + do { + while (true) { + foreach ($tokens as $token) { + for ($i = 0; $i < $token; $i++) { + echo 'hello'; + } + } + } + } while (true); + } + } + } + } + + /* + This is another c style comment 1. + This is another c style comment 2. + This is another c style comment 3. + This is another c style comment 4. + This is another c style comment 5. + */ + + /* This is a T_COMMENT + * + * + * + */ + + /** This is a T_DOC_COMMENT + */ + + /* + This T_COMMENT has a newline in it. + + */ + + public function read() + { + echo 'hello'; + + // no errors below. + $array = array( + 'this', + 'that' => array( + 'hello', + 'hello again' => array( + 'hello', + ), + ), + ); + } +} + +abstract class Test3 +{ + public function parse() + { + + foreach ($t as $ndx => $token) { + if (is_array($token)) { + echo 'here'; + } else { + $ts[] = array("token" => $token, "value" => ''); + + $last = count($ts) - 1; + + switch ($token) { + case '(': + + if ($last >= 3 && + $ts[0]['token'] != T_CLASS && + $ts[$last - 2]['token'] == T_OBJECT_OPERATOR && + $ts[$last - 3]['token'] == T_VARIABLE ) { + + + if (true) { + echo 'hello'; + } + } + array_push($braces, $token); + break; + } + } + } + } +} + +public function test() +{ + $o = <<