SAND-framework/build/bin/phploc-7.0.2.phar

3135 lines
95 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env php
<?php
if ($_SERVER['SCRIPT_NAME'] != '-') {
$phar = realpath($_SERVER['SCRIPT_NAME']);
} else {
$files = get_included_files();
$phar = $files[0];
}
define('__PHPLOC_PHAR__', str_replace(DIRECTORY_SEPARATOR, '/', $phar));
define('__PHPLOC_PHAR_ROOT__', 'phar://phploc-7.0.2.phar');
spl_autoload_register(
function ($class)
{
static $classes = NULL;
if ($classes === NULL) {
$classes = array(
'sebastianbergmann\\cliparser\\ambiguousoptionexception' => '/sebastian-cli-parser/exceptions/AmbiguousOptionException.php',
'sebastianbergmann\\cliparser\\exception' => '/sebastian-cli-parser/exceptions/Exception.php',
'sebastianbergmann\\cliparser\\optiondoesnotallowargumentexception' => '/sebastian-cli-parser/exceptions/OptionDoesNotAllowArgumentException.php',
'sebastianbergmann\\cliparser\\parser' => '/sebastian-cli-parser/Parser.php',
'sebastianbergmann\\cliparser\\requiredoptionargumentmissingexception' => '/sebastian-cli-parser/exceptions/RequiredOptionArgumentMissingException.php',
'sebastianbergmann\\cliparser\\unknownoptionexception' => '/sebastian-cli-parser/exceptions/UnknownOptionException.php',
'sebastianbergmann\\fileiterator\\facade' => '/phpunit-php-file-iterator/Facade.php',
'sebastianbergmann\\fileiterator\\factory' => '/phpunit-php-file-iterator/Factory.php',
'sebastianbergmann\\fileiterator\\iterator' => '/phpunit-php-file-iterator/Iterator.php',
'sebastianbergmann\\phploc\\analyser' => '/src/Analyser.php',
'sebastianbergmann\\phploc\\application' => '/src/CLI/Application.php',
'sebastianbergmann\\phploc\\arguments' => '/src/CLI/Arguments.php',
'sebastianbergmann\\phploc\\argumentsbuilder' => '/src/CLI/ArgumentsBuilder.php',
'sebastianbergmann\\phploc\\argumentsbuilderexception' => '/src/Exception/ArgumentsBuilderException.php',
'sebastianbergmann\\phploc\\collector' => '/src/Collector.php',
'sebastianbergmann\\phploc\\exception' => '/src/Exception/Exception.php',
'sebastianbergmann\\phploc\\log\\csv' => '/src/Log/Csv.php',
'sebastianbergmann\\phploc\\log\\json' => '/src/Log/Json.php',
'sebastianbergmann\\phploc\\log\\text' => '/src/Log/Text.php',
'sebastianbergmann\\phploc\\log\\xml' => '/src/Log/Xml.php',
'sebastianbergmann\\phploc\\publisher' => '/src/Publisher.php',
'sebastianbergmann\\phploc\\runtimeexception' => '/src/Exception/RuntimeException.php',
'sebastianbergmann\\version' => '/sebastian-version/Version.php'
);
}
$class = strtolower($class);
if (isset($classes[$class])) {
require 'phar://phploc-7.0.2.phar' . $classes[$class];
}
}
);
Phar::mapPhar('phploc-7.0.2.phar');
if (isset($_SERVER['argv'][1]) && $_SERVER['argv'][1] == '--manifest') {
print file_get_contents(__PHPLOC_PHAR_ROOT__ . '/manifest.txt');
exit;
}
exit((new \SebastianBergmann\PHPLOC\Application)->run($_SERVER['argv']));
__HALT_COMPILER(); ?>
xphploc-7.0.2.pharsrc/CLI/Arguments.phpA <00><><EFBFBD>_A Ǡ<><C7A0><EFBFBD>src/CLI/ArgumentsBuilder.php> <00><><EFBFBD>_> `<60>src/CLI/Application.php<68> <00><><EFBFBD>_<EFBFBD> <00><><EFBFBD><08>src/Collector.php"<00><><EFBFBD>_"<06><><08>src/Analyser.phpwZ<00><><EFBFBD>_wZ<00>G'<27>+src/Exception/ArgumentsBuilderException.php<68><00><><EFBFBD>_<EFBFBD>Е+
<EFBFBD>src/Exception/Exception.php[<00><><EFBFBD>_[!X<>"src/Exception/RuntimeException.phpk<00><><EFBFBD>_k<00>a <20><>src/Log/Xml.php<00><><EFBFBD>_ \<5C>B<EFBFBD>src/Log/Json.php<68><00><><EFBFBD>_<EFBFBD><00><>d<1B>src/Log/Csv.php&<00><><EFBFBD>_&A<>I<EFBFBD><49>src/Log/Text.php<68>#<00><><EFBFBD>_<EFBFBD>#<00><><EFBFBD>(<28>src/Publisher.php<68>4<00><><EFBFBD>_<EFBFBD>4,5vm<76> manifest.txtk<00><><EFBFBD>_k<00>hL<68>-sebastian-cli-parser/exceptions/Exception.phpl<00><><EFBFBD>_l@1<11><>Gsebastian-cli-parser/exceptions/OptionDoesNotAllowArgumentException.php<68><00><><EFBFBD>_<EFBFBD>5<><35><EFBFBD><EFBFBD>:sebastian-cli-parser/exceptions/UnknownOptionException.phpz<00><><EFBFBD>_z<00><><EFBFBD><EFBFBD><EFBFBD>Jsebastian-cli-parser/exceptions/RequiredOptionArgumentMissingException.php<68><00><><EFBFBD>_<EFBFBD>w~<7E><><sebastian-cli-parser/exceptions/AmbiguousOptionException.php<68><00><><EFBFBD>_<EFBFBD><00><>=<3D><>sebastian-cli-parser/Parser.php<68><00><><EFBFBD>_<EFBFBD>s<>sebastian-cli-parser/LICENSE<00><><EFBFBD>_<00><>u<>sebastian-version/Version.php<00><><EFBFBD>_A<>z*<2A>sebastian-version/LICENSE<00><><EFBFBD>_<00>Z<EFBFBD><5A><EFBFBD>%phpunit-php-file-iterator/Factory.php<68> <00><><EFBFBD>_<EFBFBD> ַ<>"<22>&phpunit-php-file-iterator/Iterator.php<68> <00><><EFBFBD>_<EFBFBD> [4eo<65>$phpunit-php-file-iterator/Facade.phpe
<00><><EFBFBD>_e
<00><>!phpunit-php-file-iterator/LICENSE<00><><EFBFBD>_<00><>.<2E><?php declare(strict_types=1);
/*
* This file is part of PHPLOC.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC;
final class Arguments
{
/**
* @psalm-var list<string>
*/
private $directories;
/**
* @psalm-var list<string>
*/
private $suffixes;
/**
* @psalm-var list<string>
*/
private $exclude;
/**
* @var bool
*/
private $countTests;
/**
* @var ?string
*/
private $csvLogfile;
/**
* @var ?string
*/
private $jsonLogfile;
/**
* @var ?string
*/
private $xmlLogfile;
/**
* @var bool
*/
private $help;
/**
* @var bool
*/
private $version;
public function __construct(array $directories, array $suffixes, array $exclude, bool $countTests, ?string $csvLogfile, ?string $jsonLogfile, ?string $xmlLogfile, bool $help, bool $version)
{
$this->directories = $directories;
$this->suffixes = $suffixes;
$this->exclude = $exclude;
$this->countTests = $countTests;
$this->csvLogfile = $csvLogfile;
$this->jsonLogfile = $jsonLogfile;
$this->xmlLogfile = $xmlLogfile;
$this->help = $help;
$this->version = $version;
}
/**
* @psalm-return list<string>
*/
public function directories(): array
{
return $this->directories;
}
/**
* @psalm-return list<string>
*/
public function suffixes(): array
{
return $this->suffixes;
}
/**
* @psalm-return list<string>
*/
public function exclude(): array
{
return $this->exclude;
}
public function countTests(): bool
{
return $this->countTests;
}
public function csvLogfile(): ?string
{
return $this->csvLogfile;
}
public function jsonLogfile(): ?string
{
return $this->jsonLogfile;
}
public function xmlLogfile(): ?string
{
return $this->xmlLogfile;
}
public function help(): bool
{
return $this->help;
}
public function version(): bool
{
return $this->version;
}
}
<?php declare(strict_types=1);
/*
* This file is part of PHPLOC.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC;
use SebastianBergmann\CliParser\Exception as CliParserException;
use SebastianBergmann\CliParser\Parser as CliParser;
final class ArgumentsBuilder
{
/**
* @throws ArgumentsBuilderException
*/
public function build(array $argv): Arguments
{
try {
$options = (new CliParser)->parse(
$argv,
'hv',
[
'suffix=',
'exclude=',
'count-tests',
'log-csv=',
'log-json=',
'log-xml=',
'help',
'version',
]
);
} catch (CliParserException $e) {
throw new ArgumentsBuilderException(
$e->getMessage(),
(int) $e->getCode(),
$e
);
}
$directories = $options[1];
$exclude = [];
$suffixes = ['.php'];
$countTests = false;
$csvLogfile = null;
$jsonLogfile = null;
$xmlLogfile = null;
$help = false;
$version = false;
foreach ($options[0] as $option) {
switch ($option[0]) {
case '--suffix':
$suffixes[] = $option[1];
break;
case '--exclude':
$exclude[] = $option[1];
break;
case '--count-tests':
$countTests = true;
break;
case '--log-csv':
$csvLogfile = $option[1];
break;
case '--log-json':
$jsonLogfile = $option[1];
break;
case '--log-xml':
$xmlLogfile = $option[1];
break;
case 'h':
case '--help':
$help = true;
break;
case 'v':
case '--version':
$version = true;
break;
}
}
if (empty($options[1]) && !$help && !$version) {
throw new ArgumentsBuilderException(
'No directory specified'
);
}
return new Arguments(
$directories,
$suffixes,
$exclude,
$countTests,
$csvLogfile,
$jsonLogfile,
$xmlLogfile,
$help,
$version,
);
}
}
<?php declare(strict_types=1);
/*
* This file is part of PHPLOC.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC;
use const PHP_EOL;
use function printf;
use SebastianBergmann\FileIterator\Facade;
use SebastianBergmann\PHPLOC\Log\Csv as CsvPrinter;
use SebastianBergmann\PHPLOC\Log\Json as JsonPrinter;
use SebastianBergmann\PHPLOC\Log\Text as TextPrinter;
use SebastianBergmann\PHPLOC\Log\Xml as XmlPrinter;
use SebastianBergmann\Version;
final class Application
{
private const VERSION = '7.0.2';
public function run(array $argv): int
{
$this->printVersion();
try {
$arguments = (new ArgumentsBuilder)->build($argv);
} catch (Exception $e) {
print PHP_EOL . $e->getMessage() . PHP_EOL;
return 1;
}
if ($arguments->version()) {
return 0;
}
print PHP_EOL;
if ($arguments->help()) {
$this->help();
return 0;
}
$files = (new Facade)->getFilesAsArray(
$arguments->directories(),
$arguments->suffixes(),
'',
$arguments->exclude()
);
if (empty($files)) {
print 'No files found to scan' . PHP_EOL;
return 1;
}
$result = (new Analyser)->countFiles($files, $arguments->countTests());
(new TextPrinter)->printResult($result, $arguments->countTests());
if ($arguments->csvLogfile()) {
$printer = new CsvPrinter;
$printer->printResult($arguments->csvLogfile(), $result);
}
if ($arguments->jsonLogfile()) {
$printer = new JsonPrinter;
$printer->printResult($arguments->jsonLogfile(), $result);
}
if ($arguments->xmlLogfile()) {
$printer = new XmlPrinter;
$printer->printResult($arguments->xmlLogfile(), $result);
}
return 0;
}
private function printVersion(): void
{
printf(
'phploc %s by Sebastian Bergmann.' . PHP_EOL,
(new Version(self::VERSION, dirname(__DIR__)))->getVersion()
);
}
private function help(): void
{
print <<<'EOT'
Usage:
phploc [options] <directory>
Options for selecting files:
--suffix <suffix> Include files with names ending in <suffix> in the analysis
(default: .php; can be given multiple times)
--exclude <path> Exclude files with <path> in their path from the analysis
(can be given multiple times)
Options for analysing files:
--count-tests Count PHPUnit test case classes and test methods
Options for report generation:
--log-csv <file> Write results in CSV format to <file>
--log-json <file> Write results in JSON format to <file>
--log-xml <file> Write results in XML format to <file>
EOT;
}
}
<?php declare(strict_types=1);
/*
* This file is part of PHPLOC.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC;
use function dirname;
class Collector
{
private $counts = [];
private $currentClassComplexity = 0;
private $currentClassLines = 0;
private $currentMethodComplexity = 0;
private $currentMethodLines = 0;
private $currentNumberOfMethods = 0;
public function getPublisher()
{
return new Publisher($this->counts);
}
public function addFile($filename): void
{
$this->increment('files');
$this->addUnique('directories', dirname($filename));
}
public function incrementLines($number): void
{
$this->increment('lines', $number);
}
public function incrementCommentLines($number): void
{
$this->increment('comment lines', $number);
}
public function incrementLogicalLines(): void
{
$this->increment('logical lines');
}
public function currentClassReset(): void
{
if ($this->currentClassComplexity > 0) {
$this->addToArray('class complexity', $this->currentClassComplexity);
$this->addToArray('class lines', $this->currentClassLines);
}
$this->currentClassComplexity = 0;
$this->currentClassLines = 0;
$this->currentNumberOfMethods = 0;
}
public function currentClassStop(): void
{
$this->addToArray('methods per class', $this->currentNumberOfMethods);
}
public function currentClassIncrementComplexity(): void
{
$this->currentClassComplexity++;
}
public function currentClassIncrementLines(): void
{
$this->currentClassLines++;
}
public function currentMethodStart(): void
{
$this->currentMethodComplexity = 1;
$this->currentMethodLines = 0;
}
public function currentClassIncrementMethods(): void
{
$this->currentNumberOfMethods++;
}
public function currentMethodIncrementComplexity(): void
{
$this->currentMethodComplexity++;
$this->increment('total method complexity');
}
public function currentMethodIncrementLines(): void
{
$this->currentMethodLines++;
}
public function currentMethodStop(): void
{
$this->addToArray('method complexity', $this->currentMethodComplexity);
$this->addToArray('method lines', $this->currentMethodLines);
}
public function incrementFunctionLines(): void
{
$this->increment('function lines');
}
public function incrementComplexity(): void
{
$this->increment('complexity');
}
public function addPossibleConstantAccesses($name): void
{
$this->addToArray('possible constant accesses', $name);
}
public function addConstant($name): void
{
$this->addToArray('constant', $name);
}
public function incrementGlobalVariableAccesses(): void
{
$this->increment('global variable accesses');
}
public function incrementSuperGlobalVariableAccesses(): void
{
$this->increment('super global variable accesses');
}
public function incrementNonStaticAttributeAccesses(): void
{
$this->increment('non-static attribute accesses');
}
public function incrementStaticAttributeAccesses(): void
{
$this->increment('static attribute accesses');
}
public function incrementNonStaticMethodCalls(): void
{
$this->increment('non-static method calls');
}
public function incrementStaticMethodCalls(): void
{
$this->increment('static method calls');
}
public function addNamespace($namespace): void
{
$this->addUnique('namespaces', $namespace);
}
public function incrementInterfaces(): void
{
$this->increment('interfaces');
}
public function incrementTraits(): void
{
$this->increment('traits');
}
public function incrementAbstractClasses(): void
{
$this->increment('abstract classes');
}
public function incrementNonFinalClasses(): void
{
$this->increment('non-final classes');
}
public function incrementFinalClasses(): void
{
$this->increment('final classes');
}
public function incrementNonStaticMethods(): void
{
$this->increment('non-static methods');
}
public function incrementStaticMethods(): void
{
$this->increment('static methods');
}
public function incrementPublicMethods(): void
{
$this->increment('public methods');
}
public function incrementProtectedMethods(): void
{
$this->increment('protected methods');
}
public function incrementPrivateMethods(): void
{
$this->increment('private methods');
}
public function incrementNamedFunctions(): void
{
$this->increment('named functions');
}
public function incrementAnonymousFunctions(): void
{
$this->increment('anonymous functions');
}
public function incrementGlobalConstants(): void
{
$this->increment('global constants');
}
public function incrementPublicClassConstants(): void
{
$this->increment('public class constants');
}
public function incrementNonPublicClassConstants(): void
{
$this->increment('non-public class constants');
}
public function incrementTestClasses(): void
{
$this->increment('test classes');
}
public function incrementTestMethods(): void
{
$this->increment('test methods');
}
private function addUnique($key, $name): void
{
$this->check($key, []);
$this->counts[$key][$name] = true;
}
private function addToArray($key, $value): void
{
$this->check($key, []);
$this->counts[$key][] = $value;
}
private function increment($key, $number = 1): void
{
$this->check($key, 0);
$this->counts[$key] += $number;
}
private function check($key, $default): void
{
if (!isset($this->counts[$key])) {
$this->counts[$key] = $default;
}
}
}
<?php declare(strict_types=1);
/*
* This file is part of PHPLOC.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC;
use const T_ABSTRACT;
use const T_BOOLEAN_AND;
use const T_BOOLEAN_OR;
use const T_CASE;
use const T_CATCH;
use const T_CLASS;
use const T_COMMENT;
use const T_CONST;
use const T_CONSTANT_ENCAPSED_STRING;
use const T_CURLY_OPEN;
use const T_DECLARE;
use const T_DOC_COMMENT;
use const T_DOLLAR_OPEN_CURLY_BRACES;
use const T_DOUBLE_COLON;
use const T_ELSEIF;
use const T_EXTENDS;
use const T_FINAL;
use const T_FOR;
use const T_FOREACH;
use const T_FUNCTION;
use const T_GLOBAL;
use const T_IF;
use const T_INTERFACE;
use const T_LOGICAL_AND;
use const T_LOGICAL_OR;
use const T_NAMESPACE;
use const T_NEW;
use const T_NS_SEPARATOR;
use const T_OBJECT_OPERATOR;
use const T_PRIVATE;
use const T_PROTECTED;
use const T_PUBLIC;
use const T_STATIC;
use const T_STRING;
use const T_TRAIT;
use const T_USE;
use const T_VARIABLE;
use const T_WHILE;
use const T_WHITESPACE;
use function array_pop;
use function count;
use function file_get_contents;
use function in_array;
use function is_array;
use function is_string;
use function rtrim;
use function str_replace;
use function strpos;
use function strtolower;
use function substr;
use function substr_count;
use function token_get_all;
use function trim;
final 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;
}
public function countFiles(array $files, bool $countTests)
{
foreach ($files as $file) {
$this->countFile($file, $countTests);
}
return $this->collector->getPublisher()->toArray();
}
public function preProcessFile(string $filename): void
{
$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)) {
break;
}
$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): void
{
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();
$isLogicalLine = true;
$isInMethod = false;
for ($i = 0; $i < $numTokens; $i++) {
if (is_string($tokens[$i])) {
$token = trim($tokens[$i]);
if ($token === ';') {
if ($isLogicalLine) {
if ($className !== null && !$testClass) {
$this->collector->currentClassIncrementLines();
if ($functionName !== null) {
$this->collector->currentMethodIncrementLines();
}
} elseif ($functionName !== null) {
$this->collector->incrementFunctionLines();
}
$this->collector->incrementLogicalLines();
}
$isLogicalLine = true;
} 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;
}
$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->currentClassStop();
$this->collector->currentClassReset();
}
}
}
continue;
}
[$token, $value] = $tokens[$i];
switch ($token) {
case T_NAMESPACE:
$namespace = $this->getNamespaceName($tokens, $i);
$this->collector->addNamespace($namespace);
$isLogicalLine = false;
break;
case T_CLASS:
case T_INTERFACE:
case T_TRAIT:
if (!$this->isClassDeclaration($tokens, $i)) {
break;
}
$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 {
$classModifierToken = $this->getPreviousNonWhitespaceNonCommentTokenPos($tokens, $i);
if ($classModifierToken !== false &&
$tokens[$classModifierToken][0] === T_ABSTRACT
) {
$this->collector->incrementAbstractClasses();
} elseif (
$classModifierToken !== false &&
$tokens[$classModifierToken][0] === T_FINAL
) {
$this->collector->incrementFinalClasses();
} else {
$this->collector->incrementNonFinalClasses();
}
}
}
break;
case T_FUNCTION:
$prev = $this->getPreviousNonWhitespaceTokenPos($tokens, $i);
if ($tokens[$prev][0] === T_USE) {
break;
}
$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();
$this->collector->currentClassIncrementMethods();
if (!$static) {
$this->collector->incrementNonStaticMethods();
} else {
$this->collector->incrementStaticMethods();
}
if ($visibility === T_PUBLIC) {
$this->collector->incrementPublicMethods();
} elseif ($visibility === T_PROTECTED) {
$this->collector->incrementProtectedMethods();
} elseif ($visibility === T_PRIVATE) {
$this->collector->incrementPrivateMethods();
}
}
}
}
break;
case T_CURLY_OPEN:
$currentBlock = T_CURLY_OPEN;
$blocks[] = $currentBlock;
break;
case T_DOLLAR_OPEN_CURLY_BRACES:
$currentBlock = T_DOLLAR_OPEN_CURLY_BRACES;
$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:
$possibleScopeToken = $this->getPreviousNonWhitespaceNonCommentTokenPos($tokens, $i);
if ($possibleScopeToken !== false
&& in_array($tokens[$possibleScopeToken][0], [T_PRIVATE, T_PROTECTED], true)
) {
$this->collector->incrementNonPublicClassConstants();
} else {
$this->collector->incrementPublicClassConstants();
}
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;
case T_USE:
case T_DECLARE:
$isLogicalLine = false;
break;
}
}
}
/**
* @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 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 (isset($tokens[$i + 1]) && 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((string) $this->classes[$className], -8) === 'testcase';
}
/**
* @param string $functionName
* @param int $visibility
* @param bool $static
* @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 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;
}
return $start + 1;
}
return false;
}
/**
* @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;
}
return $start - 1;
}
return false;
}
/**
* @return bool
*/
private function getPreviousNonWhitespaceNonCommentTokenPos(array $tokens, int $start)
{
$previousTokenIndex = $start - 1;
if (isset($tokens[$previousTokenIndex])) {
if (in_array($tokens[$previousTokenIndex][0], [
T_WHITESPACE,
T_COMMENT,
T_DOC_COMMENT,
], true)
) {
return $this->getPreviousNonWhitespaceNonCommentTokenPos($tokens, $previousTokenIndex);
}
return $previousTokenIndex;
}
return false;
}
/**
* @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);
}
}
<?php declare(strict_types=1);
/*
* This file is part of PHPLOC.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC;
use RuntimeException;
final class ArgumentsBuilderException extends RuntimeException implements Exception
{
}
<?php declare(strict_types=1);
/*
* This file is part of PHPLOC.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC;
use Throwable;
interface Exception extends Throwable
{
}
<?php declare(strict_types=1);
/*
* This file is part of PHPLOC.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* 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
{
}
<?php declare(strict_types=1);
/*
* This file is part of PHPLOC.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC\Log;
use function file_put_contents;
use DOMDocument;
final class Xml
{
/** @noinspection UnusedFunctionResultInspection */
public function printResult(string $filename, array $count): void
{
$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', (string) $count['directories'])
);
$root->appendChild(
$document->createElement('files', (string) $count['files'])
);
}
unset($count['directories'], $count['files']);
foreach ($count as $k => $v) {
$root->appendChild(
$document->createElement($k, (string) $v)
);
}
file_put_contents($filename, $document->saveXML());
}
}
<?php declare(strict_types=1);
/*
* This file is part of PHPLOC.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC\Log;
use const JSON_PRETTY_PRINT;
use function array_merge;
use function file_put_contents;
use function json_encode;
final class Json
{
public function printResult(string $filename, array $count): void
{
$directories = [];
if ($count['directories'] > 0) {
$directories = [
'directories' => $count['directories'],
'files' => $count['files'],
];
}
unset($count['directories'], $count['files']);
$report = array_merge($directories, $count);
file_put_contents(
$filename,
json_encode($report, JSON_PRETTY_PRINT)
);
}
}
<?php declare(strict_types=1);
/*
* This file is part of PHPLOC.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC\Log;
use const PHP_EOL;
use function array_values;
use function file_put_contents;
use function implode;
use InvalidArgumentException;
final class Csv
{
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',
'finalClasses' => 'Final Classes',
'nonFinalClasses' => 'Non-Final Classes',
'llocClasses' => 'Classes Length (LLOC)',
'methods' => 'Methods',
'nonStaticMethods' => 'Non-Static Methods',
'staticMethods' => 'Static Methods',
'publicMethods' => 'Public Methods',
'nonPublicMethods' => 'Non-Public Methods',
'protectedMethods' => 'Protected Methods',
'privateMethods' => 'Private Methods',
'classCcnAvg' => 'Cyclomatic Complexity / Number of Classes' /* In Text output: 'Average Complexity per Class' */,
'methodCcnAvg' => 'Cyclomatic Complexity / Number of Methods',
'functions' => 'Functions',
'namedFunctions' => 'Named Functions',
'anonymousFunctions' => 'Anonymous Functions',
'llocFunctions' => 'Functions Length (LLOC)',
'llocByNof' => 'Average Function Length (LLOC)',
'classLlocAvg' => 'Average Class Length',
'methodLlocAvg' => 'Average Method Length',
'averageMethodsPerClass' => 'Average Methods per Class',
'constants' => 'Constants',
'globalConstants' => 'Global Constants',
'classConstants' => 'Class Constants',
'publicClassConstants' => 'Public Class Constants',
'nonPublicClassConstants' => 'Non-Public 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',
];
public function printResult(string $filename, array $count): void
{
file_put_contents(
$filename,
$this->getKeysLine($count) . $this->getValuesLine($count)
);
}
private function getKeysLine(array $count): string
{
return implode(',', array_values($this->colmap)) . PHP_EOL;
}
/**
* @throws InvalidArgumentException
*/
private function getValuesLine(array $count): string
{
$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;
}
}
<?php declare(strict_types=1);
/*
* This file is part of PHPLOC.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC\Log;
use const PHP_EOL;
final class Text
{
public function printResult(array $count, bool $printTests): void
{
if ($count['directories'] > 0) {
\printf(
'Directories %10d' . PHP_EOL .
'Files %10d' . PHP_EOL . PHP_EOL,
$count['directories'],
$count['files']
);
}
$format = <<<'END'
Size
Lines of Code (LOC) %10d
Comment Lines of Code (CLOC) %10d (%.2f%%)
Non-Comment Lines of Code (NCLOC) %10d (%.2f%%)
Logical Lines of Code (LLOC) %10d (%.2f%%)
Classes %10d (%.2f%%)
Average Class Length %10d
Minimum Class Length %10d
Maximum Class Length %10d
Average Method Length %10d
Minimum Method Length %10d
Maximum Method Length %10d
Average Methods Per Class %10d
Minimum Methods Per Class %10d
Maximum Methods Per Class %10d
Functions %10d (%.2f%%)
Average Function Length %10d
Not in classes or functions %10d (%.2f%%)
Cyclomatic Complexity
Average Complexity per LLOC %10.2f
Average Complexity per Class %10.2f
Minimum Class Complexity %10.2f
Maximum Class Complexity %10.2f
Average Complexity per Method %10.2f
Minimum Method Complexity %10.2f
Maximum Method Complexity %10.2f
Dependencies
Global Accesses %10d
Global Constants %10d (%.2f%%)
Global Variables %10d (%.2f%%)
Super-Global Variables %10d (%.2f%%)
Attribute Accesses %10d
Non-Static %10d (%.2f%%)
Static %10d (%.2f%%)
Method Calls %10d
Non-Static %10d (%.2f%%)
Static %10d (%.2f%%)
Structure
Namespaces %10d
Interfaces %10d
Traits %10d
Classes %10d
Abstract Classes %10d (%.2f%%)
Concrete Classes %10d (%.2f%%)
Final Classes %10d (%.2f%%)
Non-Final Classes %10d (%.2f%%)
Methods %10d
Scope
Non-Static Methods %10d (%.2f%%)
Static Methods %10d (%.2f%%)
Visibility
Public Methods %10d (%.2f%%)
Protected Methods %10d (%.2f%%)
Private Methods %10d (%.2f%%)
Functions %10d
Named Functions %10d (%.2f%%)
Anonymous Functions %10d (%.2f%%)
Constants %10d
Global Constants %10d (%.2f%%)
Class Constants %10d (%.2f%%)
Public Constants %10d (%.2f%%)
Non-Public Constants %10d (%.2f%%)
END;
printf(
$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['averageMethodsPerClass'],
$count['minimumMethodsPerClass'],
$count['maximumMethodsPerClass'],
$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['finalClasses'],
$count['concreteClasses'] > 0 ? ($count['finalClasses'] / $count['concreteClasses']) * 100 : 0,
$count['nonFinalClasses'],
$count['concreteClasses'] > 0 ? ($count['nonFinalClasses'] / $count['concreteClasses']) * 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['protectedMethods'],
$count['methods'] > 0 ? ($count['protectedMethods'] / $count['methods']) * 100 : 0,
$count['privateMethods'],
$count['methods'] > 0 ? ($count['privateMethods'] / $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,
$count['publicClassConstants'],
$count['classConstants'] > 0 ? ($count['publicClassConstants'] / $count['classConstants']) * 100 : 0,
$count['nonPublicClassConstants'],
$count['classConstants'] > 0 ? ($count['nonPublicClassConstants'] / $count['classConstants']) * 100 : 0
);
if ($printTests) {
\printf(
PHP_EOL . 'Tests' . PHP_EOL .
' Classes %10d' . PHP_EOL .
' Methods %10d' . PHP_EOL,
$count['testClasses'],
$count['testMethods']
);
}
}
}
<?php declare(strict_types=1);
/*
* This file is part of PHPLOC.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\PHPLOC;
use function array_intersect;
use function array_sum;
use function count;
use function max;
use function min;
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 getAverageMethodsPerClass()
{
return $this->getAverage('methods per class');
}
public function getMinimumMethodsPerClass()
{
return $this->getMinimum('methods per class');
}
public function getMaximumMethodsPerClass()
{
return $this->getMaximum('methods per class');
}
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->getFinalClasses() + $this->getNonFinalClasses();
}
public function getFinalClasses()
{
return $this->getValue('final classes');
}
public function getNonFinalClasses()
{
return $this->getValue('non-final 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->getProtectedMethods() + $this->getPrivateMethods();
}
public function getProtectedMethods()
{
return $this->getValue('protected methods');
}
public function getPrivateMethods()
{
return $this->getValue('private 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 getPublicClassConstants()
{
return $this->getValue('public class constants');
}
public function getNonPublicClassConstants()
{
return $this->getValue('non-public class constants');
}
public function getClassConstants()
{
return $this->getPublicClassConstants() + $this->getNonPublicClassConstants();
}
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(),
'finalClasses' => $this->getFinalClasses(),
'nonFinalClasses' => $this->getNonFinalClasses(),
'functions' => $this->getFunctions(),
'namedFunctions' => $this->getNamedFunctions(),
'anonymousFunctions' => $this->getAnonymousFunctions(),
'methods' => $this->getMethods(),
'publicMethods' => $this->getPublicMethods(),
'nonPublicMethods' => $this->getNonPublicMethods(),
'protectedMethods' => $this->getProtectedMethods(),
'privateMethods' => $this->getPrivateMethods(),
'nonStaticMethods' => $this->getNonStaticMethods(),
'staticMethods' => $this->getStaticMethods(),
'constants' => $this->getConstants(),
'classConstants' => $this->getClassConstants(),
'publicClassConstants' => $this->getPublicClassConstants(),
'nonPublicClassConstants' => $this->getNonPublicClassConstants(),
'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(),
'averageMethodsPerClass' => $this->getAverageMethodsPerClass(),
'minimumMethodsPerClass' => $this->getMinimumMethodsPerClass(),
'maximumMethodsPerClass' => $this->getMaximumMethodsPerClass(),
'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 $this->counts[$key] ?? $default;
}
private function divide($x, $y)
{
return $y != 0 ? $x / $y : 0;
}
}
phploc/phploc: 7.0.2
phpunit/php-file-iterator: 3.0.5
sebastian/cli-parser: 1.0.1
sebastian/version: 3.0.2
<?php declare(strict_types=1);
/*
* This file is part of sebastian/cli-parser.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\CliParser;
use Throwable;
interface Exception extends Throwable
{
}
<?php declare(strict_types=1);
/*
* This file is part of sebastian/cli-parser.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\CliParser;
use function sprintf;
use RuntimeException;
final class OptionDoesNotAllowArgumentException extends RuntimeException implements Exception
{
public function __construct(string $option)
{
parent::__construct(
sprintf(
'Option "%s" does not allow an argument',
$option
)
);
}
}
<?php declare(strict_types=1);
/*
* This file is part of sebastian/cli-parser.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\CliParser;
use function sprintf;
use RuntimeException;
final class UnknownOptionException extends RuntimeException implements Exception
{
public function __construct(string $option)
{
parent::__construct(
sprintf(
'Unknown option "%s"',
$option
)
);
}
}
<?php declare(strict_types=1);
/*
* This file is part of sebastian/cli-parser.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\CliParser;
use function sprintf;
use RuntimeException;
final class RequiredOptionArgumentMissingException extends RuntimeException implements Exception
{
public function __construct(string $option)
{
parent::__construct(
sprintf(
'Required argument for option "%s" is missing',
$option
)
);
}
}
<?php declare(strict_types=1);
/*
* This file is part of sebastian/cli-parser.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\CliParser;
use function sprintf;
use RuntimeException;
final class AmbiguousOptionException extends RuntimeException implements Exception
{
public function __construct(string $option)
{
parent::__construct(
sprintf(
'Option "%s" is ambiguous',
$option
)
);
}
}
<?php declare(strict_types=1);
/*
* This file is part of sebastian/cli-parser.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\CliParser;
use function array_map;
use function array_merge;
use function array_shift;
use function array_slice;
use function assert;
use function count;
use function current;
use function explode;
use function is_array;
use function is_int;
use function is_string;
use function key;
use function next;
use function preg_replace;
use function reset;
use function sort;
use function strlen;
use function strpos;
use function strstr;
use function substr;
final class Parser
{
/**
* @psalm-param list<string> $argv
* @psalm-param list<string> $longOptions
*
* @throws AmbiguousOptionException
* @throws RequiredOptionArgumentMissingException
* @throws OptionDoesNotAllowArgumentException
* @throws UnknownOptionException
*/
public function parse(array $argv, string $shortOptions, array $longOptions = null): array
{
if (empty($argv)) {
return [[], []];
}
$options = [];
$nonOptions = [];
if ($longOptions) {
sort($longOptions);
}
if (isset($argv[0][0]) && $argv[0][0] !== '-') {
array_shift($argv);
}
reset($argv);
$argv = array_map('trim', $argv);
while (false !== $arg = current($argv)) {
$i = key($argv);
assert(is_int($i));
next($argv);
if ($arg === '') {
continue;
}
if ($arg === '--') {
$nonOptions = array_merge($nonOptions, array_slice($argv, $i + 1));
break;
}
if ($arg[0] !== '-' || (strlen($arg) > 1 && $arg[1] === '-' && !$longOptions)) {
$nonOptions[] = $arg;
continue;
}
if (strlen($arg) > 1 && $arg[1] === '-' && is_array($longOptions)) {
$this->parseLongOption(
substr($arg, 2),
$longOptions,
$options,
$argv
);
} else {
$this->parseShortOption(
substr($arg, 1),
$shortOptions,
$options,
$argv
);
}
}
return [$options, $nonOptions];
}
/**
* @throws RequiredOptionArgumentMissingException
*/
private function parseShortOption(string $arg, string $shortOptions, array &$opts, array &$args): void
{
$argLength = strlen($arg);
for ($i = 0; $i < $argLength; $i++) {
$option = $arg[$i];
$optionArgument = null;
if ($arg[$i] === ':' || ($spec = strstr($shortOptions, $option)) === false) {
throw new UnknownOptionException('-' . $option);
}
assert(is_string($spec));
if (strlen($spec) > 1 && $spec[1] === ':') {
if ($i + 1 < $argLength) {
$opts[] = [$option, substr($arg, $i + 1)];
break;
}
if (!(strlen($spec) > 2 && $spec[2] === ':')) {
$optionArgument = current($args);
if (!$optionArgument) {
throw new RequiredOptionArgumentMissingException('-' . $option);
}
assert(is_string($optionArgument));
next($args);
}
}
$opts[] = [$option, $optionArgument];
}
}
/**
* @psalm-param list<string> $longOptions
*
* @throws AmbiguousOptionException
* @throws RequiredOptionArgumentMissingException
* @throws OptionDoesNotAllowArgumentException
* @throws UnknownOptionException
*/
private function parseLongOption(string $arg, array $longOptions, array &$opts, array &$args): void
{
$count = count($longOptions);
$list = explode('=', $arg);
$option = $list[0];
$optionArgument = null;
if (count($list) > 1) {
$optionArgument = $list[1];
}
$optionLength = strlen($option);
foreach ($longOptions as $i => $longOption) {
$opt_start = substr($longOption, 0, $optionLength);
if ($opt_start !== $option) {
continue;
}
$opt_rest = substr($longOption, $optionLength);
if ($opt_rest !== '' && $i + 1 < $count && $option[0] !== '=' && strpos($longOptions[$i + 1], $option) === 0) {
throw new AmbiguousOptionException('--' . $option);
}
if (substr($longOption, -1) === '=') {
/* @noinspection StrlenInEmptyStringCheckContextInspection */
if (substr($longOption, -2) !== '==' && !strlen((string) $optionArgument)) {
if (false === $optionArgument = current($args)) {
throw new RequiredOptionArgumentMissingException('--' . $option);
}
next($args);
}
} elseif ($optionArgument) {
throw new OptionDoesNotAllowArgumentException('--' . $option);
}
$fullOption = '--' . preg_replace('/={1,2}$/', '', $longOption);
$opts[] = [$fullOption, $optionArgument];
return;
}
throw new UnknownOptionException('--' . $option);
}
}
sebastian/cli-parser
Copyright (c) 2020, Sebastian Bergmann <sebastian@phpunit.de>.
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.
<?php
/*
* This file is part of sebastian/version.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann;
final class Version
{
/**
* @var string
*/
private $path;
/**
* @var string
*/
private $release;
/**
* @var string
*/
private $version;
public function __construct(string $release, string $path)
{
$this->release = $release;
$this->path = $path;
}
public function getVersion(): string
{
if ($this->version === null) {
if (\substr_count($this->release, '.') + 1 === 3) {
$this->version = $this->release;
} else {
$this->version = $this->release . '-dev';
}
$git = $this->getGitInformation($this->path);
if ($git) {
if (\substr_count($this->release, '.') + 1 === 3) {
$this->version = $git;
} else {
$git = \explode('-', $git);
$this->version = $this->release . '-' . \end($git);
}
}
}
return $this->version;
}
/**
* @return bool|string
*/
private function getGitInformation(string $path)
{
if (!\is_dir($path . DIRECTORY_SEPARATOR . '.git')) {
return false;
}
$process = \proc_open(
'git describe --tags',
[
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
],
$pipes,
$path
);
if (!\is_resource($process)) {
return false;
}
$result = \trim(\stream_get_contents($pipes[1]));
\fclose($pipes[1]);
\fclose($pipes[2]);
$returnCode = \proc_close($process);
if ($returnCode !== 0) {
return false;
}
return $result;
}
}
Version
Copyright (c) 2013-2020, Sebastian Bergmann <sebastian@phpunit.de>.
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.
<?php declare(strict_types=1);
/*
* This file is part of phpunit/php-file-iterator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\FileIterator;
use const GLOB_ONLYDIR;
use function array_filter;
use function array_map;
use function array_merge;
use function glob;
use function is_dir;
use function is_string;
use function realpath;
use AppendIterator;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
class Factory
{
/**
* @param array|string $paths
* @param array|string $suffixes
* @param array|string $prefixes
*/
public function getFileIterator($paths, $suffixes = '', $prefixes = '', array $exclude = []): AppendIterator
{
if (is_string($paths)) {
$paths = [$paths];
}
$paths = $this->getPathsAfterResolvingWildcards($paths);
$exclude = $this->getPathsAfterResolvingWildcards($exclude);
if (is_string($prefixes)) {
if ($prefixes !== '') {
$prefixes = [$prefixes];
} else {
$prefixes = [];
}
}
if (is_string($suffixes)) {
if ($suffixes !== '') {
$suffixes = [$suffixes];
} else {
$suffixes = [];
}
}
$iterator = new AppendIterator;
foreach ($paths as $path) {
if (is_dir($path)) {
$iterator->append(
new Iterator(
$path,
new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::FOLLOW_SYMLINKS | RecursiveDirectoryIterator::SKIP_DOTS)
),
$suffixes,
$prefixes,
$exclude
)
);
}
}
return $iterator;
}
protected function getPathsAfterResolvingWildcards(array $paths): array
{
$_paths = [];
foreach ($paths as $path) {
if ($locals = glob($path, GLOB_ONLYDIR)) {
$_paths = array_merge($_paths, array_map('\realpath', $locals));
} else {
$_paths[] = realpath($path);
}
}
return array_filter($_paths);
}
}
<?php declare(strict_types=1);
/*
* This file is part of phpunit/php-file-iterator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\FileIterator;
use function array_filter;
use function array_map;
use function preg_match;
use function realpath;
use function str_replace;
use function strlen;
use function strpos;
use function substr;
use FilterIterator;
class Iterator extends FilterIterator
{
public const PREFIX = 0;
public const SUFFIX = 1;
/**
* @var string
*/
private $basePath;
/**
* @var array
*/
private $suffixes = [];
/**
* @var array
*/
private $prefixes = [];
/**
* @var array
*/
private $exclude = [];
public function __construct(string $basePath, \Iterator $iterator, array $suffixes = [], array $prefixes = [], array $exclude = [])
{
$this->basePath = realpath($basePath);
$this->prefixes = $prefixes;
$this->suffixes = $suffixes;
$this->exclude = array_filter(array_map('realpath', $exclude));
parent::__construct($iterator);
}
public function accept(): bool
{
$current = $this->getInnerIterator()->current();
$filename = $current->getFilename();
$realPath = $current->getRealPath();
if ($realPath === false) {
return false;
}
return $this->acceptPath($realPath) &&
$this->acceptPrefix($filename) &&
$this->acceptSuffix($filename);
}
private function acceptPath(string $path): bool
{
// Filter files in hidden directories by checking path that is relative to the base path.
if (preg_match('=/\.[^/]*/=', str_replace($this->basePath, '', $path))) {
return false;
}
foreach ($this->exclude as $exclude) {
if (strpos($path, $exclude) === 0) {
return false;
}
}
return true;
}
private function acceptPrefix(string $filename): bool
{
return $this->acceptSubString($filename, $this->prefixes, self::PREFIX);
}
private function acceptSuffix(string $filename): bool
{
return $this->acceptSubString($filename, $this->suffixes, self::SUFFIX);
}
private function acceptSubString(string $filename, array $subStrings, int $type): bool
{
if (empty($subStrings)) {
return true;
}
$matched = false;
foreach ($subStrings as $string) {
if (($type === self::PREFIX && strpos($filename, $string) === 0) ||
($type === self::SUFFIX &&
substr($filename, -1 * strlen($string)) === $string)) {
$matched = true;
break;
}
}
return $matched;
}
}
<?php declare(strict_types=1);
/*
* This file is part of phpunit/php-file-iterator.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace SebastianBergmann\FileIterator;
use const DIRECTORY_SEPARATOR;
use function array_unique;
use function count;
use function dirname;
use function explode;
use function is_file;
use function is_string;
use function realpath;
use function sort;
class Facade
{
/**
* @param array|string $paths
* @param array|string $suffixes
* @param array|string $prefixes
*/
public function getFilesAsArray($paths, $suffixes = '', $prefixes = '', array $exclude = [], bool $commonPath = false): array
{
if (is_string($paths)) {
$paths = [$paths];
}
$iterator = (new Factory)->getFileIterator($paths, $suffixes, $prefixes, $exclude);
$files = [];
foreach ($iterator as $file) {
$file = $file->getRealPath();
if ($file) {
$files[] = $file;
}
}
foreach ($paths as $path) {
if (is_file($path)) {
$files[] = realpath($path);
}
}
$files = array_unique($files);
sort($files);
if ($commonPath) {
return [
'commonPath' => $this->getCommonPath($files),
'files' => $files,
];
}
return $files;
}
protected function getCommonPath(array $files): string
{
$count = count($files);
if ($count === 0) {
return '';
}
if ($count === 1) {
return dirname($files[0]) . DIRECTORY_SEPARATOR;
}
$_files = [];
foreach ($files as $file) {
$_files[] = $_fileParts = explode(DIRECTORY_SEPARATOR, $file);
if (empty($_fileParts[0])) {
$_fileParts[0] = DIRECTORY_SEPARATOR;
}
}
$common = '';
$done = false;
$j = 0;
$count--;
while (!$done) {
for ($i = 0; $i < $count; $i++) {
if ($_files[$i][$j] != $_files[$i + 1][$j]) {
$done = true;
break;
}
}
if (!$done) {
$common .= $_files[0][$j];
if ($j > 0) {
$common .= DIRECTORY_SEPARATOR;
}
}
$j++;
}
return DIRECTORY_SEPARATOR . $common;
}
}
php-file-iterator
Copyright (c) 2009-2020, Sebastian Bergmann <sebastian@phpunit.de>.
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.
K2<EFBFBD>o<EFBFBD> F<>1x<31><78><0E><><EFBFBD>͵<EFBFBD>6<EFBFBD>w><3E>U<EFBFBD>Q<><03><><EFBFBD>w$<0E>jn@
<EFBFBD><EFBFBD><EFBFBD><1A><>m<EFBFBD>6)<29><><EFBFBD><EFBFBD><12><><EFBFBD>Ϣ<EFBFBD>GBMB