PK ˆ\GM7ÅÝL L .travis.ymlnu W+A„¶ language: php
php:
- 5.6
- 7.0
- 7.1
- 7.2
- master
env:
matrix:
- DEPENDENCIES="high"
- DEPENDENCIES="low"
sudo: false
before_install:
- composer self-update
- composer clear-cache
- if [ $(phpenv version-name) = "5.6" ]; then wget https://phar.phpunit.de/phpunit-5.7.phar -O phpunit.phar; fi
- if [ $(phpenv version-name) != "5.6" ]; then wget https://phar.phpunit.de/phpunit.phar; fi
install:
- if [[ "$DEPENDENCIES" = 'high' ]]; then travis_retry composer update --no-interaction --no-ansi --no-progress --no-suggest --optimize-autoloader --prefer-stable; fi
- if [[ "$DEPENDENCIES" = 'low' ]]; then travis_retry composer update --no-interaction --no-ansi --no-progress --no-suggest --optimize-autoloader --prefer-stable --prefer-lowest; fi
script:
- php phpunit.phar
notifications:
email: false
PK ˆ\GMtE߯v v .php_csnu W+A„¶
For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
EOF;
return PhpCsFixer\Config::create()
->setRiskyAllowed(true)
->setRules(
[
'array_syntax' => ['syntax' => 'short'],
'binary_operator_spaces' => [
'align_double_arrow' => true,
'align_equals' => true
],
'blank_line_after_namespace' => true,
'blank_line_before_return' => true,
'braces' => true,
'cast_spaces' => true,
'concat_space' => ['spacing' => 'one'],
'elseif' => true,
'encoding' => true,
'full_opening_tag' => true,
'function_declaration' => true,
'header_comment' => ['header' => $header, 'separate' => 'none'],
'indentation_type' => true,
'line_ending' => true,
'lowercase_constants' => true,
'lowercase_keywords' => true,
'method_argument_space' => true,
'native_function_invocation' => true,
'no_alias_functions' => true,
'no_blank_lines_after_class_opening' => true,
'no_blank_lines_after_phpdoc' => true,
'no_closing_tag' => true,
'no_empty_phpdoc' => true,
'no_empty_statement' => true,
'no_extra_consecutive_blank_lines' => true,
'no_leading_namespace_whitespace' => true,
'no_singleline_whitespace_before_semicolons' => true,
'no_spaces_after_function_name' => true,
'no_spaces_inside_parenthesis' => true,
'no_trailing_comma_in_list_call' => true,
'no_trailing_whitespace' => true,
'no_unused_imports' => true,
'no_whitespace_in_blank_line' => true,
'phpdoc_align' => true,
'phpdoc_indent' => true,
'phpdoc_no_access' => true,
'phpdoc_no_empty_return' => true,
'phpdoc_no_package' => true,
'phpdoc_scalar' => true,
'phpdoc_separation' => true,
'phpdoc_to_comment' => true,
'phpdoc_trim' => true,
'phpdoc_types' => true,
'phpdoc_var_without_name' => true,
'self_accessor' => true,
'simplified_null_return' => true,
'single_blank_line_at_eof' => true,
'single_import_per_statement' => true,
'single_line_after_imports' => true,
'single_quote' => true,
'ternary_operator_spaces' => true,
'trim_array_spaces' => true,
'visibility_required' => true,
]
)
->setFinder(
PhpCsFixer\Finder::create()
->files()
->in(__DIR__ . '/src')
->name('*.php')
);
PK ˆ\GM¢ƒô6 build/phar-autoload.php.innu W+A„¶ #!/usr/bin/env php
run();
__HALT_COMPILER();
PK ˆ\GM¡?³ß ß build/phar-manifest.phpnu W+A„¶ #!/usr/bin/env php
&1');
if (strpos($tag, '-') === false && strpos($tag, 'No names found') === false) {
print $tag;
} else {
$branch = @exec('git rev-parse --abbrev-ref HEAD');
$hash = @exec('git log -1 --format="%H"');
print $branch . '@' . $hash;
}
print "\n";
$lock = json_decode(file_get_contents(__DIR__ . '/../composer.lock'));
foreach ($lock->packages as $package) {
print $package->name . ': ' . $package->version;
if (!preg_match('/^[v= ]*(([0-9]+)(\\.([0-9]+)(\\.([0-9]+)(-([0-9]+))?(-?([a-zA-Z-+][a-zA-Z0-9\\.\\-:]*)?)?)?)?)$/', $package->version)) {
print '@' . $package->source->reference;
}
print "\n";
}
PK ˆ\GM%Z—ý ý phive.xmlnu W+A„¶
PK ˆ\GM öƒ¢¾ ¾ README.mdnu W+A„¶ [![Latest Stable Version](https://img.shields.io/packagist/v/phploc/phploc.svg?style=flat-square)](https://packagist.org/packages/phploc/phploc)
[![Build Status](https://img.shields.io/travis/sebastianbergmann/phploc/master.svg?style=flat-square)](https://travis-ci.org/sebastianbergmann/phploc)
# PHPLOC
`phploc` is a tool for quickly measuring the size and analyzing the structure of a PHP project.
## Installation
### PHP Archive (PHAR)
The easiest way to obtain PHPLOC is to download a [PHP Archive (PHAR)](http://php.net/phar) that has all required dependencies of PHPLOC bundled in a single file:
$ wget https://phar.phpunit.de/phploc.phar
$ chmod +x phploc.phar
$ mv phploc.phar /usr/local/bin/phploc
You can also immediately use the PHAR after you have downloaded it, of course:
$ wget https://phar.phpunit.de/phploc.phar
$ php phploc.phar
### Composer
You can add this tool as a local, per-project, development-time dependency to your project using [Composer](https://getcomposer.org/):
$ composer require --dev phploc/phploc
You can then invoke it using the `vendor/bin/phploc` executable.
## Usage Examples
### Analyse a directory and print the result
```
$ phploc src
phploc 4.0.0 by Sebastian Bergmann.
Directories 3
Files 10
Size
Lines of Code (LOC) 1882
Comment Lines of Code (CLOC) 255 (13.55%)
Non-Comment Lines of Code (NCLOC) 1627 (86.45%)
Logical Lines of Code (LLOC) 377 (20.03%)
Classes 351 (93.10%)
Average Class Length 35
Minimum Class Length 0
Maximum Class Length 172
Average Method Length 2
Minimum Method Length 1
Maximum Method Length 117
Functions 0 (0.00%)
Average Function Length 0
Not in classes or functions 26 (6.90%)
Cyclomatic Complexity
Average Complexity per LLOC 0.49
Average Complexity per Class 19.60
Minimum Class Complexity 1.00
Maximum Class Complexity 139.00
Average Complexity per Method 2.43
Minimum Method Complexity 1.00
Maximum Method Complexity 96.00
Dependencies
Global Accesses 0
Global Constants 0 (0.00%)
Global Variables 0 (0.00%)
Super-Global Variables 0 (0.00%)
Attribute Accesses 85
Non-Static 85 (100.00%)
Static 0 (0.00%)
Method Calls 280
Non-Static 276 (98.57%)
Static 4 (1.43%)
Structure
Namespaces 3
Interfaces 1
Traits 0
Classes 9
Abstract Classes 0 (0.00%)
Concrete Classes 9 (100.00%)
Methods 130
Scope
Non-Static Methods 130 (100.00%)
Static Methods 0 (0.00%)
Visibility
Public Methods 103 (79.23%)
Non-Public Methods 27 (20.77%)
Functions 0
Named Functions 0 (0.00%)
Anonymous Functions 0 (0.00%)
Constants 0
Global Constants 0 (0.00%)
Class Constants 0 (0.00%)
```
PK ˆ\GMÙÙèO O
.gitignorenu W+A„¶ /build/phar
/build/*.phar*
/.idea
/composer.lock
/vendor
/tools
/.php_cs.cache
PK ˆ\GMð€´æ æ phpunit.xmlnu W+A„¶
tests
src
PK ˆ\GMó †¦O O src/Collector.phpnu W+A„¶
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC;
class Collector
{
private $counts = [];
private $currentClassComplexity = 0;
private $currentClassLines = 0;
private $currentMethodComplexity = 0;
private $currentMethodLines = 0;
public function getPublisher()
{
return new Publisher($this->counts);
}
public function addFile($filename)
{
$this->increment('files');
$this->addUnique('directories', \dirname($filename));
}
public function incrementLines($number)
{
$this->increment('lines', $number);
}
public function incrementCommentLines($number)
{
$this->increment('comment lines', $number);
}
public function incrementLogicalLines()
{
$this->increment('logical lines');
}
public function currentClassReset()
{
if ($this->currentClassComplexity > 0) {
$this->addToArray('class complexity', $this->currentClassComplexity);
$this->addToArray('class lines', $this->currentClassLines);
}
$this->currentClassComplexity = 0;
$this->currentClassLines = 0;
}
public function currentClassIncrementComplexity()
{
$this->currentClassComplexity++;
}
public function currentClassIncrementLines()
{
$this->currentClassLines++;
}
public function currentMethodStart()
{
$this->currentMethodComplexity = 1;
$this->currentMethodLines = 0;
}
public function currentMethodIncrementComplexity()
{
$this->currentMethodComplexity++;
$this->increment('total method complexity');
}
public function currentMethodIncrementLines()
{
$this->currentMethodLines++;
}
public function currentMethodStop()
{
$this->addToArray('method complexity', $this->currentMethodComplexity);
$this->addToArray('method lines', $this->currentMethodLines);
}
public function incrementFunctionLines()
{
$this->increment('function lines');
}
public function incrementComplexity()
{
$this->increment('complexity');
}
public function addPossibleConstantAccesses($name)
{
$this->addToArray('possible constant accesses', $name);
}
public function addConstant($name)
{
$this->addToArray('constant', $name);
}
public function incrementGlobalVariableAccesses()
{
$this->increment('global variable accesses');
}
public function incrementSuperGlobalVariableAccesses()
{
$this->increment('super global variable accesses');
}
public function incrementNonStaticAttributeAccesses()
{
$this->increment('non-static attribute accesses');
}
public function incrementStaticAttributeAccesses()
{
$this->increment('static attribute accesses');
}
public function incrementNonStaticMethodCalls()
{
$this->increment('non-static method calls');
}
public function incrementStaticMethodCalls()
{
$this->increment('static method calls');
}
public function addNamespace($namespace)
{
$this->addUnique('namespaces', $namespace);
}
public function incrementInterfaces()
{
$this->increment('interfaces');
}
public function incrementTraits()
{
$this->increment('traits');
}
public function incrementAbstractClasses()
{
$this->increment('abstract classes');
}
public function incrementConcreteClasses()
{
$this->increment('concrete classes');
}
public function incrementNonStaticMethods()
{
$this->increment('non-static methods');
}
public function incrementStaticMethods()
{
$this->increment('static methods');
}
public function incrementPublicMethods()
{
$this->increment('public methods');
}
public function incrementNonPublicMethods()
{
$this->increment('non-public methods');
}
public function incrementNamedFunctions()
{
$this->increment('named functions');
}
public function incrementAnonymousFunctions()
{
$this->increment('anonymous functions');
}
public function incrementGlobalConstants()
{
$this->increment('global constants');
}
public function incrementClassConstants()
{
$this->increment('class constants');
}
public function incrementTestClasses()
{
$this->increment('test classes');
}
public function incrementTestMethods()
{
$this->increment('test methods');
}
private function addUnique($key, $name)
{
$this->check($key, []);
$this->counts[$key][$name] = true;
}
private function addToArray($key, $value)
{
$this->check($key, []);
$this->counts[$key][] = $value;
}
private function increment($key, $number = 1)
{
$this->check($key, 0);
$this->counts[$key] += $number;
}
private function check($key, $default)
{
if (!isset($this->counts[$key])) {
$this->counts[$key] = $default;
}
}
}
PK ˆ\GM
F‡–S S " src/Exception/RuntimeException.phpnu W+A„¶
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC;
class RuntimeException extends \RuntimeException implements Exception
{
}
PK ˆ\GMõ_ŠÃ! ! src/Exception/Exception.phpnu W+A„¶
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC;
interface Exception
{
}
PK ˆ\GM®XAävO vO src/Analyser.phpnu W+A„¶
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC;
/**
* PHPLOC code analyser.
*/
class Analyser
{
/**
* @var Collector
*/
private $collector;
/**
* @var array
*/
private $classes = [];
/**
* @var array
*/
private $superGlobals = [
'$_ENV' => true,
'$_POST' => true,
'$_GET' => true,
'$_COOKIE' => true,
'$_SERVER' => true,
'$_FILES' => true,
'$_REQUEST' => true,
'$HTTP_ENV_VARS' => true,
'$HTTP_POST_VARS' => true,
'$HTTP_GET_VARS' => true,
'$HTTP_COOKIE_VARS' => true,
'$HTTP_SERVER_VARS' => true,
'$HTTP_POST_FILES' => true
];
public function __construct()
{
$this->collector = new Collector();
}
/**
* Processes a set of files.
*
* @param array $files
* @param bool $countTests
*
* @return array
*/
public function countFiles(array $files, $countTests)
{
foreach ($files as $file) {
$this->countFile($file, $countTests);
}
return $this->collector->getPublisher()->toArray();
}
/**
* Pre-processes a single file.
*
* @param string $filename
*/
public function preProcessFile($filename)
{
$tokens = \token_get_all(\file_get_contents($filename));
$numTokens = \count($tokens);
$namespace = false;
for ($i = 0; $i < $numTokens; $i++) {
if (\is_string($tokens[$i])) {
continue;
}
switch ($tokens[$i][0]) {
case T_NAMESPACE:
$namespace = $this->getNamespaceName($tokens, $i);
break;
case T_CLASS:
if (!$this->isClassDeclaration($tokens, $i)) {
continue;
}
$className = $this->getClassName($namespace, $tokens, $i);
if (isset($tokens[$i + 4]) && \is_array($tokens[$i + 4]) &&
$tokens[$i + 4][0] == T_EXTENDS) {
$parent = $this->getClassName($namespace, $tokens, $i + 4);
} else {
$parent = null;
}
$this->classes[$className] = $parent;
break;
}
}
}
/**
* Processes a single file.
*
* @param string $filename
* @param bool $countTests
*/
public function countFile($filename, $countTests)
{
if ($countTests) {
$this->preProcessFile($filename);
}
$buffer = \file_get_contents($filename);
$this->collector->incrementLines(\substr_count($buffer, "\n"));
$tokens = \token_get_all($buffer);
$numTokens = \count($tokens);
unset($buffer);
$this->collector->addFile($filename);
$blocks = [];
$currentBlock = false;
$namespace = false;
$className = null;
$functionName = null;
$testClass = false;
$this->collector->currentClassReset();
$isInMethod = false;
for ($i = 0; $i < $numTokens; $i++) {
if (\is_string($tokens[$i])) {
$token = \trim($tokens[$i]);
if ($token == ';') {
if ($className !== null && !$testClass) {
$this->collector->currentClassIncrementLines();
if ($functionName !== null) {
$this->collector->currentMethodIncrementLines();
}
} elseif ($functionName !== null) {
$this->collector->incrementFunctionLines();
}
$this->collector->incrementLogicalLines();
} elseif ($token == '?' && !$testClass) {
if ($className !== null) {
$this->collector->currentClassIncrementComplexity();
$this->collector->currentMethodIncrementComplexity();
}
$this->collector->incrementComplexity();
} elseif ($token == '{') {
if ($currentBlock == T_CLASS) {
$block = $className;
} elseif ($currentBlock == T_FUNCTION) {
$block = $functionName;
} else {
$block = false;
}
\array_push($blocks, $block);
$currentBlock = false;
} elseif ($token == '}') {
$block = \array_pop($blocks);
if ($block !== false && $block !== null) {
if ($block == $functionName) {
$functionName = null;
if ($isInMethod) {
$this->collector->currentMethodStop();
$isInMethod = false;
}
} elseif ($block == $className) {
$className = null;
$testClass = false;
$this->collector->currentClassReset();
}
}
}
continue;
}
list($token, $value) = $tokens[$i];
switch ($token) {
case T_NAMESPACE:
$namespace = $this->getNamespaceName($tokens, $i);
$this->collector->addNamespace($namespace);
break;
case T_CLASS:
case T_INTERFACE:
case T_TRAIT:
if (!$this->isClassDeclaration($tokens, $i)) {
continue;
}
$this->collector->currentClassReset();
$this->collector->currentClassIncrementComplexity();
$className = $this->getClassName($namespace, $tokens, $i);
$currentBlock = T_CLASS;
if ($token == T_TRAIT) {
$this->collector->incrementTraits();
} elseif ($token == T_INTERFACE) {
$this->collector->incrementInterfaces();
} else {
if ($countTests && $this->isTestClass($className)) {
$testClass = true;
$this->collector->incrementTestClasses();
} else {
if (isset($tokens[$i - 2]) &&
\is_array($tokens[$i - 2]) &&
$tokens[$i - 2][0] == T_ABSTRACT) {
$this->collector->incrementAbstractClasses();
} else {
$this->collector->incrementConcreteClasses();
}
}
}
break;
case T_FUNCTION:
$prev = $this->getPreviousNonWhitespaceTokenPos($tokens, $i);
if ($tokens[$prev][0] === T_USE) {
continue;
}
$currentBlock = T_FUNCTION;
$next = $this->getNextNonWhitespaceTokenPos($tokens, $i);
if (!\is_array($tokens[$next]) && $tokens[$next] == '&') {
$next = $this->getNextNonWhitespaceTokenPos($tokens, $next);
}
if (\is_array($tokens[$next]) &&
$tokens[$next][0] == T_STRING) {
$functionName = $tokens[$next][1];
} else {
$currentBlock = 'anonymous function';
$functionName = 'anonymous function';
$this->collector->incrementAnonymousFunctions();
}
if ($currentBlock == T_FUNCTION) {
if ($className === null &&
$functionName != 'anonymous function') {
$this->collector->incrementNamedFunctions();
} else {
$static = false;
$visibility = T_PUBLIC;
for ($j = $i; $j > 0; $j--) {
if (\is_string($tokens[$j])) {
if ($tokens[$j] == '{' ||
$tokens[$j] == '}' ||
$tokens[$j] == ';') {
break;
}
continue;
}
if (isset($tokens[$j][0])) {
switch ($tokens[$j][0]) {
case T_PRIVATE:
$visibility = T_PRIVATE;
break;
case T_PROTECTED:
$visibility = T_PROTECTED;
break;
case T_STATIC:
$static = true;
break;
}
}
}
if ($testClass &&
$this->isTestMethod($functionName, $visibility, $static, $tokens, $i)) {
$this->collector->incrementTestMethods();
} elseif (!$testClass) {
$isInMethod = true;
$this->collector->currentMethodStart();
if (!$static) {
$this->collector->incrementNonStaticMethods();
} else {
$this->collector->incrementStaticMethods();
}
if ($visibility == T_PUBLIC) {
$this->collector->incrementPublicMethods();
} else {
$this->collector->incrementNonPublicMethods();
}
}
}
}
break;
case T_CURLY_OPEN:
$currentBlock = T_CURLY_OPEN;
\array_push($blocks, $currentBlock);
break;
case T_DOLLAR_OPEN_CURLY_BRACES:
$currentBlock = T_DOLLAR_OPEN_CURLY_BRACES;
\array_push($blocks, $currentBlock);
break;
case T_IF:
case T_ELSEIF:
case T_FOR:
case T_FOREACH:
case T_WHILE:
case T_CASE:
case T_CATCH:
case T_BOOLEAN_AND:
case T_LOGICAL_AND:
case T_BOOLEAN_OR:
case T_LOGICAL_OR:
if (!$testClass) {
if ($isInMethod) {
$this->collector->currentClassIncrementComplexity();
$this->collector->currentMethodIncrementComplexity();
}
$this->collector->incrementComplexity();
}
break;
case T_COMMENT:
case T_DOC_COMMENT:
// We want to count all intermediate lines before the token ends
// But sometimes a new token starts after a newline, we don't want to count that.
// That happened with /* */ and /** */, but not with // since it'll end at the end
$this->collector->incrementCommentLines(\substr_count(\rtrim($value, "\n"), "\n") + 1);
break;
case T_CONST:
$this->collector->incrementClassConstants();
break;
case T_STRING:
if ($value == 'define') {
$this->collector->incrementGlobalConstants();
$j = $i + 1;
while (isset($tokens[$j]) && $tokens[$j] != ';') {
if (\is_array($tokens[$j]) &&
$tokens[$j][0] == T_CONSTANT_ENCAPSED_STRING) {
$this->collector->addConstant(\str_replace('\'', '', $tokens[$j][1]));
break;
}
$j++;
}
} else {
$this->collector->addPossibleConstantAccesses($value);
}
break;
case T_DOUBLE_COLON:
case T_OBJECT_OPERATOR:
$n = $this->getNextNonWhitespaceTokenPos($tokens, $i);
$nn = $this->getNextNonWhitespaceTokenPos($tokens, $n);
if ($n && $nn &&
isset($tokens[$n][0]) &&
($tokens[$n][0] == T_STRING ||
$tokens[$n][0] == T_VARIABLE) &&
$tokens[$nn] == '(') {
if ($token == T_DOUBLE_COLON) {
$this->collector->incrementStaticMethodCalls();
} else {
$this->collector->incrementNonStaticMethodCalls();
}
} else {
if ($token == T_DOUBLE_COLON &&
$tokens[$n][0] == T_VARIABLE) {
$this->collector->incrementStaticAttributeAccesses();
} elseif ($token == T_OBJECT_OPERATOR) {
$this->collector->incrementNonStaticAttributeAccesses();
}
}
break;
case T_GLOBAL:
$this->collector->incrementGlobalVariableAccesses();
break;
case T_VARIABLE:
if ($value == '$GLOBALS') {
$this->collector->incrementGlobalVariableAccesses();
} elseif (isset($this->superGlobals[$value])) {
$this->collector->incrementSuperGlobalVariableAccesses();
}
break;
}
}
}
/**
* @param array $tokens
* @param int $i
*
* @return string
*/
private function getNamespaceName(array $tokens, $i)
{
if (isset($tokens[$i + 2][1])) {
$namespace = $tokens[$i + 2][1];
for ($j = $i + 3;; $j += 2) {
if (isset($tokens[$j]) && $tokens[$j][0] == T_NS_SEPARATOR) {
$namespace .= '\\' . $tokens[$j + 1][1];
} else {
break;
}
}
return $namespace;
}
return false;
}
/**
* @param string $namespace
* @param array $tokens
* @param int $i
*
* @return string
*/
private function getClassName($namespace, array $tokens, $i)
{
$i += 2;
if (!isset($tokens[$i][1])) {
return 'invalid class name';
}
$className = $tokens[$i][1];
$namespaced = $className === '\\';
while (\is_array($tokens[$i + 1]) && $tokens[$i + 1][0] !== T_WHITESPACE) {
$className .= $tokens[++$i][1];
}
if (!$namespaced && $namespace !== false) {
$className = $namespace . '\\' . $className;
}
return \strtolower($className);
}
/**
* @param string $className
*
* @return bool
*/
private function isTestClass($className)
{
$parent = $this->classes[$className];
$count = 0;
// Check ancestry for PHPUnit_Framework_TestCase.
while ($parent !== null) {
$count++;
if ($count > 100) {
// Prevent infinite loops and just bail
break;
}
if ($parent == 'phpunit_framework_testcase' ||
$parent == '\\phpunit_framework_testcase' ||
// TODO: Recognize PHPUnit\Framework\TestCase when it is imported
$parent == 'phpunit\\framework\\testcase' ||
$parent == '\\phpunit\\framework\\testcase') {
return true;
}
if (isset($this->classes[$parent]) && $parent !== $this->classes[$parent]) {
$parent = $this->classes[$parent];
} else {
// Class has a parent that is declared in a file
// that was not pre-processed.
break;
}
}
// Fallback: Treat the class as a test case class if the name
// of the parent class ends with "TestCase".
return \substr($this->classes[$className], -8) === 'testcase';
}
/**
* @param string $functionName
* @param int $visibility
* @param bool $static
* @param array $tokens
* @param int $currentToken
*
* @return bool
*/
private function isTestMethod($functionName, $visibility, $static, array $tokens, $currentToken)
{
if ($static || $visibility != T_PUBLIC) {
return false;
}
if (\strpos($functionName, 'test') === 0) {
return true;
}
while ($tokens[$currentToken][0] != T_DOC_COMMENT) {
if ($tokens[$currentToken] == '{' || $tokens[$currentToken] == '}') {
return false;
}
--$currentToken;
}
return \strpos($tokens[$currentToken][1], '@test') !== false ||
\strpos($tokens[$currentToken][1], '@scenario') !== false;
}
/**
* @param array $tokens
* @param int $start
*
* @return bool
*/
private function getNextNonWhitespaceTokenPos(array $tokens, $start)
{
if (isset($tokens[$start + 1])) {
if (isset($tokens[$start + 1][0]) &&
$tokens[$start + 1][0] == T_WHITESPACE &&
isset($tokens[$start + 2])) {
return $start + 2;
} else {
return $start + 1;
}
}
return false;
}
/**
* @param array $tokens
* @param int $start
*
* @return bool
*/
private function getPreviousNonWhitespaceTokenPos(array $tokens, $start)
{
if (isset($tokens[$start - 1])) {
if (isset($tokens[$start - 1][0]) &&
$tokens[$start - 1][0] == T_WHITESPACE &&
isset($tokens[$start - 2])) {
return $start - 2;
} else {
return $start - 1;
}
}
return false;
}
/**
* @param array $tokens
* @param int $i
*
* @return bool
*/
private function isClassDeclaration(array $tokens, $i)
{
$n = $this->getPreviousNonWhitespaceTokenPos($tokens, $i);
return !isset($tokens[$n])
|| !\is_array($tokens[$n])
|| !\in_array($tokens[$n][0], [T_DOUBLE_COLON, T_NEW], true);
}
}
PK ˆ\GMC¼§ê&- &- src/Publisher.phpnu W+A„¶
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC;
class Publisher
{
private $counts;
public function __construct(array $counts)
{
$this->counts = $counts;
}
public function getDirectories()
{
return $this->getCount('directories') - 1;
}
public function getFiles()
{
return $this->getValue('files');
}
public function getLines()
{
return $this->getValue('lines');
}
public function getCommentLines()
{
return $this->getValue('comment lines');
}
public function getNonCommentLines()
{
return $this->getLines() - $this->getCommentLines();
}
public function getLogicalLines()
{
return $this->getValue('logical lines');
}
public function getClassLines()
{
return $this->getSum('class lines');
}
public function getAverageClassLength()
{
return $this->getAverage('class lines');
}
public function getMinimumClassLength()
{
return $this->getMinimum('class lines');
}
public function getMaximumClassLength()
{
return $this->getMaximum('class lines');
}
public function getAverageMethodLength()
{
return $this->getAverage('method lines');
}
public function getMinimumMethodLength()
{
return $this->getMinimum('method lines');
}
public function getMaximumMethodLength()
{
return $this->getMaximum('method lines');
}
public function getFunctionLines()
{
return $this->getValue('function lines');
}
public function getAverageFunctionLength()
{
return $this->divide($this->getFunctionLines(), $this->getFunctions());
}
public function getNotInClassesOrFunctions()
{
return $this->getLogicalLines() - $this->getClassLines() - $this->getFunctionLines();
}
public function getComplexity()
{
return $this->getValue('complexity');
}
public function getMethodComplexity()
{
return $this->getValue('total method complexity');
}
public function getAverageComplexityPerLogicalLine()
{
return $this->divide($this->getComplexity(), $this->getLogicalLines());
}
public function getAverageComplexityPerClass()
{
return $this->getAverage('class complexity');
}
public function getMinimumClassComplexity()
{
return $this->getMinimum('class complexity');
}
public function getMaximumClassComplexity()
{
return $this->getMaximum('class complexity');
}
public function getAverageComplexityPerMethod()
{
return $this->getAverage('method complexity');
}
public function getMinimumMethodComplexity()
{
return $this->getMinimum('method complexity');
}
public function getMaximumMethodComplexity()
{
return $this->getMaximum('method complexity');
}
public function getGlobalAccesses()
{
return $this->getGlobalConstantAccesses() + $this->getGlobalVariableAccesses() + $this->getSuperGlobalVariableAccesses();
}
public function getGlobalConstantAccesses()
{
return \count(\array_intersect($this->getValue('possible constant accesses', []), $this->getValue('constant', [])));
}
public function getGlobalVariableAccesses()
{
return $this->getValue('global variable accesses');
}
public function getSuperGlobalVariableAccesses()
{
return $this->getValue('super global variable accesses');
}
public function getAttributeAccesses()
{
return $this->getNonStaticAttributeAccesses() + $this->getStaticAttributeAccesses();
}
public function getNonStaticAttributeAccesses()
{
return $this->getValue('non-static attribute accesses');
}
public function getStaticAttributeAccesses()
{
return $this->getValue('static attribute accesses');
}
public function getMethodCalls()
{
return $this->getNonStaticMethodCalls() + $this->getStaticMethodCalls();
}
public function getNonStaticMethodCalls()
{
return $this->getValue('non-static method calls');
}
public function getStaticMethodCalls()
{
return $this->getValue('static method calls');
}
public function getNamespaces()
{
return $this->getCount('namespaces');
}
public function getInterfaces()
{
return $this->getValue('interfaces');
}
public function getTraits()
{
return $this->getValue('traits');
}
public function getClasses()
{
return $this->getAbstractClasses() + $this->getConcreteClasses();
}
public function getAbstractClasses()
{
return $this->getValue('abstract classes');
}
public function getConcreteClasses()
{
return $this->getValue('concrete classes');
}
public function getMethods()
{
return $this->getNonStaticMethods() + $this->getStaticMethods();
}
public function getNonStaticMethods()
{
return $this->getValue('non-static methods');
}
public function getStaticMethods()
{
return $this->getValue('static methods');
}
public function getPublicMethods()
{
return $this->getValue('public methods');
}
public function getNonPublicMethods()
{
return $this->getValue('non-public methods');
}
public function getFunctions()
{
return $this->getNamedFunctions() + $this->getAnonymousFunctions();
}
public function getNamedFunctions()
{
return $this->getValue('named functions');
}
public function getAnonymousFunctions()
{
return $this->getValue('anonymous functions');
}
public function getConstants()
{
return $this->getGlobalConstants() + $this->getClassConstants();
}
public function getGlobalConstants()
{
return $this->getValue('global constants');
}
public function getClassConstants()
{
return $this->getValue('class constants');
}
public function getTestClasses()
{
return $this->getValue('test classes');
}
public function getTestMethods()
{
return $this->getValue('test methods');
}
public function toArray()
{
return [
'files' => $this->getFiles(),
'loc' => $this->getLines(),
'lloc' => $this->getLogicalLines(),
'llocClasses' => $this->getClassLines(),
'llocFunctions' => $this->getFunctionLines(),
'llocGlobal' => $this->getNotInClassesOrFunctions(),
'cloc' => $this->getCommentLines(),
'ccn' => $this->getComplexity(),
'ccnMethods' => $this->getMethodComplexity(),
'interfaces' => $this->getInterfaces(),
'traits' => $this->getTraits(),
'classes' => $this->getClasses(),
'abstractClasses' => $this->getAbstractClasses(),
'concreteClasses' => $this->getConcreteClasses(),
'functions' => $this->getFunctions(),
'namedFunctions' => $this->getNamedFunctions(),
'anonymousFunctions' => $this->getAnonymousFunctions(),
'methods' => $this->getMethods(),
'publicMethods' => $this->getPublicMethods(),
'nonPublicMethods' => $this->getNonPublicMethods(),
'nonStaticMethods' => $this->getNonStaticMethods(),
'staticMethods' => $this->getStaticMethods(),
'constants' => $this->getConstants(),
'classConstants' => $this->getClassConstants(),
'globalConstants' => $this->getGlobalConstants(),
'testClasses' => $this->getTestClasses(),
'testMethods' => $this->getTestMethods(),
'ccnByLloc' => $this->getAverageComplexityPerLogicalLine(),
'llocByNof' => $this->getAverageFunctionLength(),
'methodCalls' => $this->getMethodCalls(),
'staticMethodCalls' => $this->getStaticMethodCalls(),
'instanceMethodCalls' => $this->getNonStaticMethodCalls(),
'attributeAccesses' => $this->getAttributeAccesses(),
'staticAttributeAccesses' => $this->getStaticAttributeAccesses(),
'instanceAttributeAccesses' => $this->getNonStaticAttributeAccesses(),
'globalAccesses' => $this->getGlobalAccesses(),
'globalVariableAccesses' => $this->getGlobalVariableAccesses(),
'superGlobalVariableAccesses' => $this->getSuperGlobalVariableAccesses(),
'globalConstantAccesses' => $this->getGlobalConstantAccesses(),
'directories' => $this->getDirectories(),
'classCcnMin' => $this->getMinimumClassComplexity(),
'classCcnAvg' => $this->getAverageComplexityPerClass(),
'classCcnMax' => $this->getMaximumClassComplexity(),
'classLlocMin' => $this->getMinimumClassLength(),
'classLlocAvg' => $this->getAverageClassLength(),
'classLlocMax' => $this->getMaximumClassLength(),
'methodCcnMin' => $this->getMinimumMethodComplexity(),
'methodCcnAvg' => $this->getAverageComplexityPerMethod(),
'methodCcnMax' => $this->getMaximumMethodComplexity(),
'methodLlocMin' => $this->getMinimumMethodLength(),
'methodLlocAvg' => $this->getAverageMethodLength(),
'methodLlocMax' => $this->getMaximumMethodLength(),
'namespaces' => $this->getNamespaces(),
'ncloc' => $this->getNonCommentLines(),
];
}
private function getAverage($key)
{
return $this->divide($this->getSum($key), $this->getCount($key));
}
private function getCount($key)
{
return isset($this->counts[$key]) ? \count($this->counts[$key]) : 0;
}
private function getSum($key)
{
return isset($this->counts[$key]) ? \array_sum($this->counts[$key]) : 0;
}
private function getMaximum($key)
{
return isset($this->counts[$key]) ? \max($this->counts[$key]) : 0;
}
private function getMinimum($key)
{
return isset($this->counts[$key]) ? \min($this->counts[$key]) : 0;
}
private function getValue($key, $default = 0)
{
return isset($this->counts[$key]) ? $this->counts[$key] : $default;
}
private function divide($x, $y)
{
return $y != 0 ? $x / $y : 0;
}
}
PK ˆ\GMF§X5! 5! src/Log/Text.phpnu W+A„¶
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC\Log;
use Symfony\Component\Console\Output\OutputInterface;
/**
* A ResultPrinter for the TextUI.
*/
class Text
{
/**
* Prints a result set.
*
* @param OutputInterface $output
* @param array $count
* @param bool $printTests
*/
public function printResult(OutputInterface $output, array $count, $printTests)
{
if ($count['directories'] > 0) {
$output->write(
\sprintf(
"Directories %10d\n" .
"Files %10d\n\n",
$count['directories'],
$count['files']
)
);
}
$format = <<write(
\sprintf(
$format,
$count['loc'],
$count['cloc'],
$count['loc'] > 0 ? ($count['cloc'] / $count['loc']) * 100 : 0,
$count['ncloc'],
$count['loc'] > 0 ? ($count['ncloc'] / $count['loc']) * 100 : 0,
$count['lloc'],
$count['loc'] > 0 ? ($count['lloc'] / $count['loc']) * 100 : 0,
$count['llocClasses'],
$count['lloc'] > 0 ? ($count['llocClasses'] / $count['lloc']) * 100 : 0,
$count['classLlocAvg'],
$count['classLlocMin'],
$count['classLlocMax'],
$count['methodLlocAvg'],
$count['methodLlocMin'],
$count['methodLlocMax'],
$count['llocFunctions'],
$count['lloc'] > 0 ? ($count['llocFunctions'] / $count['lloc']) * 100 : 0,
$count['llocByNof'],
$count['llocGlobal'],
$count['lloc'] > 0 ? ($count['llocGlobal'] / $count['lloc']) * 100 : 0,
$count['ccnByLloc'],
$count['classCcnAvg'],
$count['classCcnMin'],
$count['classCcnMax'],
$count['methodCcnAvg'],
$count['methodCcnMin'],
$count['methodCcnMax'],
$count['globalAccesses'],
$count['globalConstantAccesses'],
$count['globalAccesses'] > 0 ? ($count['globalConstantAccesses'] / $count['globalAccesses']) * 100 : 0,
$count['globalVariableAccesses'],
$count['globalAccesses'] > 0 ? ($count['globalVariableAccesses'] / $count['globalAccesses']) * 100 : 0,
$count['superGlobalVariableAccesses'],
$count['globalAccesses'] > 0 ? ($count['superGlobalVariableAccesses'] / $count['globalAccesses']) * 100 : 0,
$count['attributeAccesses'],
$count['instanceAttributeAccesses'],
$count['attributeAccesses'] > 0 ? ($count['instanceAttributeAccesses'] / $count['attributeAccesses']) * 100 : 0,
$count['staticAttributeAccesses'],
$count['attributeAccesses'] > 0 ? ($count['staticAttributeAccesses'] / $count['attributeAccesses']) * 100 : 0,
$count['methodCalls'],
$count['instanceMethodCalls'],
$count['methodCalls'] > 0 ? ($count['instanceMethodCalls'] / $count['methodCalls']) * 100 : 0,
$count['staticMethodCalls'],
$count['methodCalls'] > 0 ? ($count['staticMethodCalls'] / $count['methodCalls']) * 100 : 0,
$count['namespaces'],
$count['interfaces'],
$count['traits'],
$count['classes'],
$count['abstractClasses'],
$count['classes'] > 0 ? ($count['abstractClasses'] / $count['classes']) * 100 : 0,
$count['concreteClasses'],
$count['classes'] > 0 ? ($count['concreteClasses'] / $count['classes']) * 100 : 0,
$count['methods'],
$count['nonStaticMethods'],
$count['methods'] > 0 ? ($count['nonStaticMethods'] / $count['methods']) * 100 : 0,
$count['staticMethods'],
$count['methods'] > 0 ? ($count['staticMethods'] / $count['methods']) * 100 : 0,
$count['publicMethods'],
$count['methods'] > 0 ? ($count['publicMethods'] / $count['methods']) * 100 : 0,
$count['nonPublicMethods'],
$count['methods'] > 0 ? ($count['nonPublicMethods'] / $count['methods']) * 100 : 0,
$count['functions'],
$count['namedFunctions'],
$count['functions'] > 0 ? ($count['namedFunctions'] / $count['functions']) * 100 : 0,
$count['anonymousFunctions'],
$count['functions'] > 0 ? ($count['anonymousFunctions'] / $count['functions']) * 100 : 0,
$count['constants'],
$count['globalConstants'],
$count['constants'] > 0 ? ($count['globalConstants'] / $count['constants']) * 100 : 0,
$count['classConstants'],
$count['constants'] > 0 ? ($count['classConstants'] / $count['constants']) * 100 : 0
)
);
if ($printTests) {
$output->write(
\sprintf(
"\nTests\n" .
" Classes %10d\n" .
" Methods %10d\n",
$count['testClasses'],
$count['testMethods']
)
);
}
}
}
PK ˆ\GM"‚ù. . src/Log/Csv.phpnu W+A„¶
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC\Log;
/**
* A CSV ResultPrinter for the TextUI.
*/
class Csv
{
/**
* Mapping between internal and human-readable metric names
*
* @var array
*/
private $colmap = [
'directories' => 'Directories',
'files' => 'Files',
'loc' => 'Lines of Code (LOC)',
'ccnByLloc' => 'Cyclomatic Complexity / Lines of Code',
'cloc' => 'Comment Lines of Code (CLOC)',
'ncloc' => 'Non-Comment Lines of Code (NCLOC)',
'lloc' => 'Logical Lines of Code (LLOC)',
'llocGlobal' => 'LLOC outside functions or classes',
'namespaces' => 'Namespaces',
'interfaces' => 'Interfaces',
'traits' => 'Traits',
'classes' => 'Classes',
'abstractClasses' => 'Abstract Classes',
'concreteClasses' => 'Concrete Classes',
'llocClasses' => 'Classes Length (LLOC)',
'methods' => 'Methods',
'nonStaticMethods' => 'Non-Static Methods',
'staticMethods' => 'Static Methods',
'publicMethods' => 'Public Methods',
'nonPublicMethods' => 'Non-Public Methods',
'methodCcnAvg' => 'Cyclomatic Complexity / Number of Methods',
'functions' => 'Functions',
'namedFunctions' => 'Named Functions',
'anonymousFunctions' => 'Anonymous Functions',
'llocFunctions' => 'Functions Length (LLOC)',
'llocByNof' => 'Average Function Length (LLOC)',
'constants' => 'Constants',
'globalConstants' => 'Global Constants',
'classConstants' => 'Class Constants',
'attributeAccesses' => 'Attribute Accesses',
'instanceAttributeAccesses' => 'Non-Static Attribute Accesses',
'staticAttributeAccesses' => 'Static Attribute Accesses',
'methodCalls' => 'Method Calls',
'instanceMethodCalls' => 'Non-Static Method Calls',
'staticMethodCalls' => 'Static Method Calls',
'globalAccesses' => 'Global Accesses',
'globalVariableAccesses' => 'Global Variable Accesses',
'superGlobalVariableAccesses' => 'Super-Global Variable Accesses',
'globalConstantAccesses' => 'Global Constant Accesses',
'testClasses' => 'Test Classes',
'testMethods' => 'Test Methods'
];
/**
* Prints a result set.
*
* @param string $filename
* @param array $count
*/
public function printResult($filename, array $count)
{
\file_put_contents(
$filename,
$this->getKeysLine($count) . $this->getValuesLine($count)
);
}
/**
* @param array $count
*
* @return string
*/
protected function getKeysLine(array $count)
{
return \implode(',', \array_values($this->colmap)) . PHP_EOL;
}
/**
* @param array $count
*
* @throws \InvalidArgumentException
*
* @return string
*/
protected function getValuesLine(array $count)
{
$values = [];
foreach ($this->colmap as $key => $name) {
if (isset($count[$key])) {
$values[] = $count[$key];
} else {
throw new \InvalidArgumentException('Attempted to print row with missing keys');
}
}
return '"' . \implode('","', $values) . '"' . PHP_EOL;
}
}
PK ˆ\GM ª†û src/Log/Xml.phpnu W+A„¶
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC\Log;
/**
* An XML ResultPrinter for the TextUI.
*/
class Xml
{
/**
* Prints a result set.
*
* @param string $filename
* @param array $count
*/
public function printResult($filename, array $count)
{
$document = new \DOMDocument('1.0', 'UTF-8');
$document->formatOutput = true;
$root = $document->createElement('phploc');
$document->appendChild($root);
if ($count['directories'] > 0) {
$root->appendChild(
$document->createElement('directories', $count['directories'])
);
$root->appendChild(
$document->createElement('files', $count['files'])
);
}
unset($count['directories']);
unset($count['files']);
foreach ($count as $k => $v) {
$root->appendChild(
$document->createElement($k, $v)
);
}
\file_put_contents($filename, $document->saveXML());
}
}
PK ˆ\GML Öj| | src/CLI/Command.phpnu W+A„¶
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC\CLI;
use SebastianBergmann\FinderFacade\FinderFacade;
use SebastianBergmann\PHPLOC\Analyser;
use SebastianBergmann\PHPLOC\Log\Csv;
use SebastianBergmann\PHPLOC\Log\Text;
use SebastianBergmann\PHPLOC\Log\Xml;
use Symfony\Component\Console\Command\Command as AbstractCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class Command extends AbstractCommand
{
/**
* Configures the current command.
*/
protected function configure()
{
$this->setName('phploc')
->setDefinition(
[
new InputArgument(
'values',
InputArgument::IS_ARRAY
)
]
)
->addOption(
'names',
null,
InputOption::VALUE_REQUIRED,
'A comma-separated list of file names to check',
['*.php']
)
->addOption(
'names-exclude',
null,
InputOption::VALUE_REQUIRED,
'A comma-separated list of file names to exclude',
[]
)
->addOption(
'count-tests',
null,
InputOption::VALUE_NONE,
'Count PHPUnit test case classes and test methods'
)
->addOption(
'exclude',
null,
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
'Exclude a directory from code analysis'
)
->addOption(
'log-csv',
null,
InputOption::VALUE_REQUIRED,
'Write result in CSV format to file'
)
->addOption(
'log-xml',
null,
InputOption::VALUE_REQUIRED,
'Write result in XML format to file'
);
}
/**
* Executes the current command.
*
* @param InputInterface $input An InputInterface instance
* @param OutputInterface $output An OutputInterface instance
*
* @return null|int null or 0 if everything went fine, or an error code
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$count = $this->count(
$input->getArgument('values'),
$input->getOption('exclude'),
$this->handleCSVOption($input, 'names'),
$this->handleCSVOption($input, 'names-exclude'),
$input->getOption('count-tests')
);
if (!$count) {
$output->writeln('No files found to scan');
exit(1);
}
$printer = new Text;
$printer->printResult(
$output,
$count,
$input->getOption('count-tests')
);
if ($input->getOption('log-csv')) {
$printer = new Csv;
$printer->printResult($input->getOption('log-csv'), $count);
}
if ($input->getOption('log-xml')) {
$printer = new Xml;
$printer->printResult($input->getOption('log-xml'), $count);
}
}
private function count(array $arguments, $excludes, $names, $namesExclude, $countTests)
{
try {
$finder = new FinderFacade($arguments, $excludes, $names, $namesExclude);
$files = $finder->findFiles();
} catch (\InvalidArgumentException $ex) {
return false;
}
if (empty($files)) {
return false;
}
$analyser = new Analyser;
return $analyser->countFiles($files, $countTests);
}
/**
* @param InputInterface $input
* @param string $option
*
* @return array
*/
private function handleCSVOption(InputInterface $input, $option)
{
$result = $input->getOption($option);
return \is_array($result) ? $result : \explode(',', $result);
}
}
PK ˆ\GM .¨üy y src/CLI/Application.phpnu W+A„¶
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC\CLI;
use SebastianBergmann\Version;
use Symfony\Component\Console\Application as AbstractApplication;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\ArrayInput;
/**
* TextUI frontend for PHPLOC.
*/
class Application extends AbstractApplication
{
public function __construct()
{
$version = new Version('4.0.1', \dirname(\dirname(__DIR__)));
parent::__construct('phploc', $version->getVersion());
}
/**
* Gets the name of the command based on input.
*
* @param InputInterface $input The input interface
*
* @return string The command name
*/
protected function getCommandName(InputInterface $input)
{
return 'phploc';
}
/**
* Gets the default commands that should always be available.
*
* @return array An array of default Command instances
*/
protected function getDefaultCommands()
{
$defaultCommands = parent::getDefaultCommands();
$defaultCommands[] = new Command;
return $defaultCommands;
}
/**
* Overridden so that the application doesn't expect the command
* name to be the first argument.
*/
public function getDefinition()
{
$inputDefinition = parent::getDefinition();
$inputDefinition->setArguments();
return $inputDefinition;
}
/**
* Runs the current application.
*
* @param InputInterface $input An Input instance
* @param OutputInterface $output An Output instance
*
* @return int 0 if everything went fine, or an error code
*/
public function doRun(InputInterface $input, OutputInterface $output)
{
$this->disableXdebug();
if (!$input->hasParameterOption('--quiet')) {
$output->write(
\sprintf(
"phploc %s by Sebastian Bergmann.\n\n",
$this->getVersion()
)
);
}
if ($input->hasParameterOption('--version') ||
$input->hasParameterOption('-V')) {
exit;
}
if (!$input->getFirstArgument()) {
$input = new ArrayInput(['--help']);
}
parent::doRun($input, $output);
}
private function disableXdebug()
{
if (!\extension_loaded('xdebug')) {
return;
}
\ini_set('xdebug.scream', 0);
\ini_set('xdebug.max_nesting_level', 8192);
\ini_set('xdebug.show_exception_trace', 0);
\ini_set('xdebug.show_error_trace', 0);
\xdebug_disable();
}
}
PK ˆ\GMrsX .gitattributesnu W+A„¶ *.php diff=php
PK ˆ\GMIª| phplocnu W+A„¶ #!/usr/bin/env php
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
$loaded = false;
foreach (array(__DIR__ . '/../../autoload.php', __DIR__ . '/vendor/autoload.php') as $file) {
if (file_exists($file)) {
require $file;
$loaded = true;
break;
}
}
if (!$loaded) {
die(
'You need to set up the project dependencies using the following commands:' . PHP_EOL .
'wget http://getcomposer.org/composer.phar' . PHP_EOL .
'php composer.phar install' . PHP_EOL
);
}
$application = new SebastianBergmann\PHPLOC\CLI\Application;
$application->run();
PK ˆ\GM7†ãN N ChangeLog.mdnu W+A„¶ # Changes in PHPLOC
All notable changes in PHPLOC are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles.
## [4.0.1] - 2017-11-18
### Changed
* This tool is now compatible with Symfony Console 4
## [4.0.0] - 2017-06-06
### Removed
* Removed the '--git-repository' option (and the corresponding functionality)
* Removed the '--progress' option (and the corresponding functionality)
## [3.0.1] - 2016-04-25
* Fixed [#139](https://github.com/sebastianbergmann/phploc/issues/139): Introduction of `T_USE` in `Analyser.php` gives `PHP Notice: Undefined index: ccn`
* Fixed [#141](https://github.com/sebastianbergmann/phploc/issues/141): `Undefined index: ccn in phar:///usr/local/bin/phploc/src/Analyser.php on line 507`
### Fixed
## [3.0.0] - 2016-01-13
[4.0.1]: https://github.com/sebastianbergmann/phploc/compare/4.0.0...4.0.1
[4.0.0]: https://github.com/sebastianbergmann/phploc/compare/3.0...4.0.0
[3.0.1]: https://github.com/sebastianbergmann/phploc/compare/3.0.0...3.0.1
[3.0.0]: https://github.com/sebastianbergmann/phploc/compare/2.1.5...3.0.0
PK ˆ\GMï÷ØÛ build.xmlnu W+A„¶
PK ˆ\GM/-
à à tests/Log/SingleTest.phpnu W+A„¶
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC;
use PHPUnit\Framework\TestCase;
class SingleTest extends TestCase
{
/**
* @var \SebastianBergmann\PHPLOC\Log\Csv
*/
private $single;
private $sample_row = [
'directories' => 1,
'files' => 2,
'loc' => 3,
'ccnByLloc' => 4,
'cloc' => 5,
'ncloc' => 6,
'lloc' => 7,
'llocGlobal' => 8,
'namespaces' => 9,
'interfaces' => 10,
'traits' => 11,
'classes' => 12,
'abstractClasses' => 13,
'concreteClasses' => 14,
'llocClasses' => 15,
'methods' => 16,
'nonStaticMethods' => 17,
'staticMethods' => 18,
'publicMethods' => 19,
'nonPublicMethods' => 20,
'methodCcnAvg' => 21,
'functions' => 22,
'namedFunctions' => 23,
'anonymousFunctions' => 24,
'llocFunctions' => 25,
'llocByNof' => 26,
'constants' => 27,
'globalConstants' => 28,
'classConstants' => 29,
'attributeAccesses' => 30,
'instanceAttributeAccesses' => 31,
'staticAttributeAccesses' => 32,
'methodCalls' => 33,
'instanceMethodCalls' => 34,
'staticMethodCalls' => 35,
'globalAccesses' => 36,
'globalVariableAccesses' => 37,
'superGlobalVariableAccesses' => 38,
'globalConstantAccesses' => 39,
'testClasses' => 40,
'testMethods' => 41
];
protected function setUp()
{
$this->single = new \SebastianBergmann\PHPLOC\Log\Csv;
}
public function testPrintedResultContainsHeadings()
{
\ob_start();
$this->single->printResult('php://output', $this->sample_row);
$output = \ob_get_clean();
$this->assertRegExp('#Directories,Files.+$#is', $output, 'Printed result does not contain a heading line');
}
public function testPrintedResultContainsData()
{
\ob_start();
$this->single->printResult('php://output', $this->sample_row);
$output = \ob_get_clean();
$this->assertRegExp('#"1","2".+$#is', $output, 'Printed result does not contain a value line');
}
public function testPrintedResultContainsEqualNumHeadingsAndValues()
{
\ob_start();
$this->single->printResult('php://output', $this->sample_row);
$output = \ob_get_clean();
$rows = \explode("\n", $output);
$headings = \explode(',', $rows[0]);
$vals = \explode(',', $rows[1]);
$this->assertEquals(
\count($headings),
\count($vals),
'Printed result does not contain same number of headings and values'
);
}
public function testExactlyTwoRowsArePrinted()
{
\ob_start();
$this->single->printResult('php://output', $this->sample_row);
$output = \ob_get_clean();
$rows = \explode("\n", \trim($output));
$this->assertEquals(2, \count($rows), 'Printed result contained more or less than expected 2 rows');
}
/**
* @expectedException \InvalidArgumentException
*/
public function testPrintPartialRow()
{
$count = $this->sample_row;
unset($count['llocByNof']);
try {
\ob_start();
$this->single->printResult('php://output', $count);
} finally {
\ob_end_clean();
}
$this->fail('No exception was raised for malformed input var');
}
}
PK ˆ\GM¯DÎåß( ß( tests/AnalyzerTest.phpnu W+A„¶
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC;
use PHPUnit\Framework\TestCase;
class AnalyserTest extends TestCase
{
/**
* @var Analyser
*/
private $analyser;
protected function setUp()
{
$this->analyser = new Analyser;
}
public function testWithoutTests()
{
$this->assertEquals(
[
'files' => 1,
'loc' => 75,
'lloc' => 26,
'llocClasses' => 22,
'llocFunctions' => 1,
'llocGlobal' => 3,
'cloc' => 7,
'ccn' => 2,
'ccnMethods' => 2,
'interfaces' => 1,
'traits' => 0,
'classes' => 2,
'abstractClasses' => 1,
'concreteClasses' => 1,
'functions' => 2,
'namedFunctions' => 1,
'anonymousFunctions' => 1,
'methods' => 4,
'publicMethods' => 2,
'nonPublicMethods' => 2,
'nonStaticMethods' => 3,
'staticMethods' => 1,
'constants' => 2,
'classConstants' => 1,
'globalConstants' => 1,
'testClasses' => 0,
'testMethods' => 0,
'ccnByLloc' => 0.08,
'llocByNof' => 0.5,
'methodCalls' => 6,
'staticMethodCalls' => 4,
'instanceMethodCalls' => 2,
'attributeAccesses' => 6,
'staticAttributeAccesses' => 4,
'instanceAttributeAccesses' => 2,
'globalAccesses' => 4,
'globalVariableAccesses' => 2,
'superGlobalVariableAccesses' => 1,
'globalConstantAccesses' => 1,
'directories' => 0,
'namespaces' => 1,
'ncloc' => 68,
'classCcnMin' => 1,
'classCcnAvg' => 1.65,
'classCcnMax' => 3,
'methodCcnMin' => 1,
'methodCcnAvg' => 1.65,
'methodCcnMax' => 2,
'classLlocMin' => 0,
'classLlocAvg' => 7.3,
'classLlocMax' => 22,
'methodLlocMin' => 4,
'methodLlocAvg' => 5.6,
'methodLlocMax' => 7
],
$this->analyser->countFiles(
[__DIR__ . '/_files/source.php'],
false
),
'',
0.1
);
}
public function testWithTests()
{
$this->assertEquals(
[
'files' => 2,
'loc' => 98,
'lloc' => 26,
'llocClasses' => 22,
'llocFunctions' => 1,
'llocGlobal' => 3,
'cloc' => 11,
'ccn' => 2,
'ccnMethods' => 2,
'interfaces' => 1,
'traits' => 0,
'classes' => 2,
'abstractClasses' => 1,
'concreteClasses' => 1,
'functions' => 2,
'namedFunctions' => 1,
'anonymousFunctions' => 1,
'methods' => 4,
'publicMethods' => 2,
'nonPublicMethods' => 2,
'nonStaticMethods' => 3,
'staticMethods' => 1,
'constants' => 2,
'classConstants' => 1,
'globalConstants' => 1,
'testClasses' => 1,
'testMethods' => 2,
'ccnByLloc' => 0.08,
'llocByNof' => 0.5,
'methodCalls' => 6,
'staticMethodCalls' => 4,
'instanceMethodCalls' => 2,
'attributeAccesses' => 6,
'staticAttributeAccesses' => 4,
'instanceAttributeAccesses' => 2,
'globalAccesses' => 4,
'globalVariableAccesses' => 2,
'superGlobalVariableAccesses' => 1,
'globalConstantAccesses' => 1,
'directories' => 0,
'namespaces' => 1,
'ncloc' => 87,
'classCcnMin' => 1,
'classCcnAvg' => 1.5,
'classCcnMax' => 3,
'methodCcnMin' => 1,
'methodCcnAvg' => 1.66,
'methodCcnMax' => 2,
'classLlocMin' => 0,
'classLlocAvg' => 5.5,
'classLlocMax' => 22,
'methodLlocMin' => 4,
'methodLlocAvg' => 5.6,
'methodLlocMax' => 7
],
$this->analyser->countFiles(
[
__DIR__ . '/_files/source.php',
__DIR__ . '/_files/tests.php'
],
true
),
'',
0.1
);
}
public function testFilesThatExtendPHPUnitTestCaseAreCountedAsTests()
{
$result = $this->analyser->countFiles(
[
__DIR__ . '/_files/tests.php'
],
true
);
$this->assertEquals(1, $result['testClasses']);
}
public function testFilesThatExtendPHPUnitTestCaseAreCountedAsTests2()
{
$result = $this->analyser->countFiles(
[
__DIR__ . '/_files/tests_old.php'
],
true
);
$this->assertEquals(1, $result['testClasses']);
}
public function testFilesThatIndirectlyExtendPHPUnitTestCaseAreCountedAsTests()
{
$result = $this->analyser->countFiles(
[
__DIR__ . '/_files/twoTestsThatIndirectlyExtendOldPHPUnitTestCase.php'
],
true
);
$this->assertEquals(3, $result['testClasses']);
}
public function testFilesThatIndirectlyExtendPHPUnitTestCaseAreCountedAsTests2()
{
$result = $this->analyser->countFiles(
[
__DIR__ . '/_files/twoTestsThatIndirectlyExtendPHPUnitTestCase.php'
],
true
);
$this->assertEquals(3, $result['testClasses']);
}
public function testTraitsAreCountedCorrectly()
{
$result = $this->analyser->countFiles(
[
__DIR__ . '/_files/trait.php'
],
false
);
$this->assertEquals(1, $result['traits']);
}
/**
* @ticket 64
*/
public function testIssue64IsFixed()
{
$result = $this->analyser->countFiles(
[
__DIR__ . '/_files/issue_62.php'
],
false
);
$this->assertEquals(1, $result['cloc']);
}
/**
* @ticket 112
*/
public function testIssue112IsFixed()
{
$result = $this->analyser->countFiles(
[
__DIR__ . '/_files/issue_112.php'
],
false
);
$this->assertEquals(5, $result['loc']);
}
/**
* @ticket 126
* @dataProvider issue126Provider
*/
public function testIssue126IsFixed($fileNumber, $cloc)
{
$file = __DIR__ . '/_files/issue_126/issue_126_' . $fileNumber . '.php';
$result = $this->analyser->countFiles([$file], false);
$assertString = \sprintf('Failed asserting that %s matches expected %s in issue_126_%d.php',
$result['cloc'],
$cloc,
$fileNumber
);
$this->assertEquals($cloc, $result['cloc'], $assertString);
}
public function issue126Provider()
{
// issue_126_X.php => CLOC
return [
[1, 1],
[2, 1],
[3, 1],
[4, 2],
[5, 3],
[6, 3],
[7, 3],
];
}
/**
* @requires PHP 7
* @ticket 138
*/
public function testIssue138IsFixed()
{
\error_reporting(E_ALL);
$result = $this->analyser->countFiles(
[
__DIR__ . '/_files/issue_138.php'
],
false
);
$this->assertSame(1, $result['classes']);
}
/**
* @ticket 139
*/
public function testIssue139IsFixed()
{
\error_reporting(E_ALL);
$result = $this->analyser->countFiles(
[
__DIR__ . '/_files/issue_139.php'
],
false
);
$this->assertEquals(1, $result['anonymousFunctions']);
}
}
PK ˆ\GM|I±/A A tests/_files/issue_112.phpnu W+A„¶ m();
$o->$m();
$o->a;
$o->$a;
}
public function aPublicMethod()
{
$a = true ? true : false;
c::m();
c::$m();
c::$a;
c::$a;
c::aConstant;
}
protected function aProtectedMethod()
{
if (true) {
}
$c::m();
$c::$m();
$c::$a;
$c::$a;
}
private function aPrivateMethod()
{
$function = function() {};
echo "This is {$great}";
echo "This is ${great}";
}
}
PK ˆ\GM€@zÉ6 6 tests/_files/trait.phpnu W+A„¶ .
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Sebastian Bergmann nor the names of his
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
PK ˆ\GMoHœ£K K
composer.jsonnu W+A„¶ {
"name": "phploc/phploc",
"description": "A tool for quickly measuring the size of a PHP project.",
"homepage": "https://github.com/sebastianbergmann/phploc",
"license": "BSD-3-Clause",
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"support": {
"issues": "https://github.com/sebastianbergmann/phploc/issues"
},
"require": {
"php": "^5.6 || ^7.0",
"sebastian/finder-facade": "^1.1",
"sebastian/version": "^2.0",
"symfony/console": "^2.7|^3.0|^4.0"
},
"autoload": {
"classmap": [
"src/"
]
},
"bin": [
"phploc"
],
"extra": {
"branch-alias": {
"dev-master": "4.0-dev"
}
}
}
PK ˆ\GM7ÅÝL L .travis.ymlnu W+A„¶ PK ˆ\GMtE߯v v ‡ .php_csnu W+A„¶ PK ˆ\GM¢ƒô6 4 build/phar-autoload.php.innu W+A„¶ PK ˆ\GM¡?³ß ß build/phar-manifest.phpnu W+A„¶ PK ˆ\GM%Z—ý ý D phive.xmlnu W+A„¶ PK ˆ\GM öƒ¢¾ ¾ z README.mdnu W+A„¶ PK ˆ\GMÙÙèO O
q( .gitignorenu W+A„¶ PK ˆ\GMð€´æ æ ú( phpunit.xmlnu W+A„¶ PK ˆ\GMó †¦O O , src/Collector.phpnu W+A„¶ PK ˆ\GM
F‡–S S " «A src/Exception/RuntimeException.phpnu W+A„¶ PK ˆ\GMõ_ŠÃ! ! PC src/Exception/Exception.phpnu W+A„¶ PK ˆ\GM®XAävO vO ¼D src/Analyser.phpnu W+A„¶ PK ˆ\GMC¼§ê&- &- r” src/Publisher.phpnu W+A„¶ PK ˆ\GMF§X5! 5! ÙÁ src/Log/Text.phpnu W+A„¶ PK ˆ\GM"‚ù. . Nã src/Log/Csv.phpnu W+A„¶ PK ˆ\GM ª†û »ó src/Log/Xml.phpnu W+A„¶ PK ˆ\GML Öj| | üø src/CLI/Command.phpnu W+A„¶ PK ˆ\GM .¨üy y »
src/CLI/Application.phpnu W+A„¶ PK ˆ\GMrsX { .gitattributesnu W+A„¶ PK ˆ\GMIª| È phplocnu W+A„¶ PK ˆ\GM7†ãN N
ChangeLog.mdnu W+A„¶ PK ˆ\GMï÷ØÛ — build.xmlnu W+A„¶ PK ˆ\GM/-
à à ë0 tests/Log/SingleTest.phpnu W+A„¶ PK ˆ\GM¯DÎåß( ß( B tests/AnalyzerTest.phpnu W+A„¶ PK ˆ\GM|I±/A A 8k tests/_files/issue_112.phpnu W+A„¶ PK ˆ\GMv»qYž ž <