pax_global_header00006660000000000000000000000064137677320070014526gustar00rootroot0000000000000052 comment=816c79a4c66137254c56ca18c0d0fcbce092cfe3 phploc-7.0.2/000077500000000000000000000000001376773200700130215ustar00rootroot00000000000000phploc-7.0.2/.github/000077500000000000000000000000001376773200700143615ustar00rootroot00000000000000phploc-7.0.2/.github/FUNDING.yml000066400000000000000000000000321376773200700161710ustar00rootroot00000000000000github: sebastianbergmann phploc-7.0.2/.github/workflows/000077500000000000000000000000001376773200700164165ustar00rootroot00000000000000phploc-7.0.2/.github/workflows/ci.yml000066400000000000000000000040531376773200700175360ustar00rootroot00000000000000# https://help.github.com/en/categories/automating-your-workflow-with-github-actions on: - "pull_request" - "push" name: "CI" jobs: coding-guidelines: name: "Coding Guidelines" runs-on: "ubuntu-latest" steps: - name: "Checkout" uses: "actions/checkout@v2" - name: "Run friendsofphp/php-cs-fixer" run: "./tools/php-cs-fixer fix --diff-format=udiff --dry-run --show-progress=dots --using-cache=no --verbose" type-checker: name: "Type Checker" runs-on: "ubuntu-latest" steps: - name: "Checkout" uses: "actions/checkout@v2" - name: "Update dependencies with composer" run: "./tools/composer update --no-ansi --no-interaction --no-progress" - name: "Run vimeo/psalm" run: "./tools/psalm --config=.psalm/config.xml --no-progress --shepherd --show-info=false --stats" tests: name: "Tests" runs-on: "ubuntu-latest" strategy: matrix: php-version: - "7.3" - "7.4" - "8.0" - "8.1" steps: - name: "Checkout" uses: "actions/checkout@v2" - name: "Install PHP with extensions" uses: "shivammathur/setup-php@v2" with: php-version: "${{ matrix.php-version }}" coverage: "pcov" - name: "Cache dependencies installed with composer" uses: "actions/cache@v1" with: path: "~/.composer/cache" key: "php${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('**/composer.json') }}" restore-keys: "php${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-" - name: "Install dependencies with composer" run: "./tools/composer update --no-ansi --no-interaction --no-progress" - name: "Run tests with phpunit/phpunit" run: "./tools/phpunit --coverage-clover=coverage.xml" - name: "Send code coverage report to Codecov.io" env: CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}" run: "bash <(curl -s https://codecov.io/bash) || true" phploc-7.0.2/.gitignore000066400000000000000000000001301376773200700150030ustar00rootroot00000000000000/build/phar /build/*.phar* /.idea /composer.lock /vendor /.php_cs.cache /.phpunit.cache phploc-7.0.2/.phive/000077500000000000000000000000001376773200700142125ustar00rootroot00000000000000phploc-7.0.2/.phive/phars.xml000066400000000000000000000011111376773200700160430ustar00rootroot00000000000000 phploc-7.0.2/.php_cs.dist000066400000000000000000000206141376773200700152430ustar00rootroot00000000000000 For the full copyright and license information, please view the LICENSE file that was distributed with this source code. EOF; $finder = PhpCsFixer\Finder::create() ->files() ->in(__DIR__ . '/src') ->in(__DIR__ . '/tests/unit'); return PhpCsFixer\Config::create() ->setFinder($finder) ->setRiskyAllowed(true) ->setRules([ 'align_multiline_comment' => true, 'array_indentation' => true, 'array_syntax' => ['syntax' => 'short'], 'binary_operator_spaces' => [ 'operators' => [ '=' => 'align_single_space_minimal', '=>' => 'align_single_space_minimal', ], ], 'blank_line_after_namespace' => true, 'blank_line_before_statement' => [ 'statements' => [ 'break', 'continue', 'declare', 'default', 'die', 'do', 'exit', 'for', 'foreach', 'goto', 'if', 'include', 'include_once', 'require', 'require_once', 'return', 'switch', 'throw', 'try', 'while', 'yield', ], ], 'braces' => true, 'cast_spaces' => true, 'class_attributes_separation' => ['elements' => ['const', 'method', 'property']], 'combine_consecutive_issets' => true, 'combine_consecutive_unsets' => true, 'compact_nullable_typehint' => true, 'concat_space' => ['spacing' => 'one'], 'constant_case' => true, 'declare_equal_normalize' => ['space' => 'none'], 'declare_strict_types' => true, 'dir_constant' => true, 'elseif' => true, 'encoding' => true, 'explicit_indirect_variable' => true, 'explicit_string_variable' => true, 'full_opening_tag' => true, 'fully_qualified_strict_types' => true, 'function_declaration' => true, 'global_namespace_import' => [ 'import_classes' => true, 'import_constants' => true, 'import_functions' => true, ], 'header_comment' => ['header' => $header, 'separate' => 'none'], 'heredoc_to_nowdoc' => true, 'increment_style' => [ 'style' => PhpCsFixer\Fixer\Operator\IncrementStyleFixer::STYLE_POST, ], 'indentation_type' => true, 'is_null' => true, 'line_ending' => true, 'list_syntax' => ['syntax' => 'short'], 'logical_operators' => true, 'lowercase_keywords' => true, 'lowercase_static_reference' => true, 'magic_constant_casing' => true, 'magic_method_casing' => true, 'method_argument_space' => ['ensure_fully_multiline' => true], 'modernize_types_casting' => true, 'multiline_comment_opening_closing' => true, 'multiline_whitespace_before_semicolons' => true, 'native_constant_invocation' => false, 'native_function_casing' => false, 'native_function_invocation' => false, 'native_function_type_declaration_casing' => true, 'new_with_braces' => false, 'no_alias_functions' => true, 'no_alternative_syntax' => true, 'no_blank_lines_after_class_opening' => true, 'no_blank_lines_after_phpdoc' => true, 'no_blank_lines_before_namespace' => true, 'no_closing_tag' => true, 'no_empty_comment' => true, 'no_empty_phpdoc' => true, 'no_empty_statement' => true, 'no_extra_blank_lines' => true, 'no_homoglyph_names' => true, 'no_leading_import_slash' => true, 'no_leading_namespace_whitespace' => true, 'no_mixed_echo_print' => ['use' => 'print'], 'no_multiline_whitespace_around_double_arrow' => true, 'no_null_property_initialization' => true, 'no_php4_constructor' => true, 'no_short_bool_cast' => true, 'no_short_echo_tag' => true, 'no_singleline_whitespace_before_semicolons' => true, 'no_spaces_after_function_name' => true, 'no_spaces_around_offset' => true, 'no_spaces_inside_parenthesis' => true, 'no_superfluous_elseif' => true, 'no_superfluous_phpdoc_tags' => [ 'allow_mixed' => true, ], 'no_trailing_comma_in_list_call' => true, 'no_trailing_comma_in_singleline_array' => true, 'no_trailing_whitespace' => true, 'no_trailing_whitespace_in_comment' => true, 'no_unneeded_control_parentheses' => true, 'no_unneeded_curly_braces' => true, 'no_unneeded_final_method' => true, 'no_unreachable_default_argument_value' => true, 'no_unset_on_property' => true, 'no_unused_imports' => true, 'no_useless_else' => true, 'no_useless_return' => true, 'no_whitespace_before_comma_in_array' => true, 'no_whitespace_in_blank_line' => true, 'non_printable_character' => true, 'normalize_index_brace' => true, 'object_operator_without_whitespace' => true, 'ordered_class_elements' => [ 'order' => [ 'use_trait', 'constant_public', 'constant_protected', 'constant_private', 'property_public_static', 'property_protected_static', 'property_private_static', 'property_public', 'property_protected', 'property_private', 'method_public_static', 'construct', 'destruct', 'magic', 'phpunit', 'method_public', 'method_protected', 'method_private', 'method_protected_static', 'method_private_static', ], ], 'ordered_imports' => [ 'imports_order' => [ PhpCsFixer\Fixer\Import\OrderedImportsFixer::IMPORT_TYPE_CONST, PhpCsFixer\Fixer\Import\OrderedImportsFixer::IMPORT_TYPE_FUNCTION, PhpCsFixer\Fixer\Import\OrderedImportsFixer::IMPORT_TYPE_CLASS, ] ], 'ordered_interfaces' => [ 'direction' => 'ascend', 'order' => 'alpha', ], 'phpdoc_add_missing_param_annotation' => false, 'phpdoc_align' => true, 'phpdoc_annotation_without_dot' => true, 'phpdoc_indent' => true, 'phpdoc_no_access' => true, 'phpdoc_no_empty_return' => true, 'phpdoc_no_package' => true, 'phpdoc_order' => true, 'phpdoc_return_self_reference' => true, 'phpdoc_scalar' => true, 'phpdoc_separation' => true, 'phpdoc_single_line_var_spacing' => true, 'phpdoc_summary' => true, 'phpdoc_to_comment' => true, 'phpdoc_trim' => true, 'phpdoc_trim_consecutive_blank_line_separation' => true, 'phpdoc_types' => ['groups' => ['simple', 'meta']], 'phpdoc_types_order' => true, 'phpdoc_var_without_name' => true, 'pow_to_exponentiation' => true, 'protected_to_private' => true, 'return_assignment' => true, 'return_type_declaration' => ['space_before' => 'none'], 'self_accessor' => true, 'self_static_accessor' => true, 'semicolon_after_instruction' => true, 'set_type_to_cast' => true, 'short_scalar_cast' => true, 'simple_to_complex_string_variable' => true, 'simplified_null_return' => false, 'single_blank_line_at_eof' => true, 'single_import_per_statement' => true, 'single_line_after_imports' => true, 'single_quote' => true, 'standardize_not_equals' => true, 'strict_param' => true, 'ternary_to_null_coalescing' => true, 'trailing_comma_in_multiline_array' => true, 'trim_array_spaces' => true, 'unary_operator_spaces' => true, 'visibility_required' => [ 'elements' => [ 'const', 'method', 'property', ], ], 'void_return' => true, 'whitespace_after_comma_in_array' => true, ]); phploc-7.0.2/.psalm/000077500000000000000000000000001376773200700142135ustar00rootroot00000000000000phploc-7.0.2/.psalm/baseline.xml000066400000000000000000000441761376773200700165330ustar00rootroot00000000000000 false $start + 2 $start + 1 $start - 2 $start - 1 $previousTokenIndex bool bool bool $next $n countFiles $file $className $tokens[$currentToken][1] $tokens[$currentToken][1] $tokens[$i + 2][1] $tokens[$j][0] $tokens[$j + 1][1] $tokens[$i + 1][0] $tokens[++$i][1] $tokens[$currentToken][0] $tokens[$currentToken][1] $tokens[$currentToken][1] $tokens[$start + 1][0] $tokens[$start - 1][0] $tokens[$previousTokenIndex][0] $this->classes[$parent] $file $namespace $className $parent $parent string toArray $tokens[$j + 1][1] $namespace $className $className $namespace $namespace $namespace $namespace $visibility === T_PRIVATE $namespace !== false !$namespaced && $namespace !== false $block === $functionName $block === $className $result $result $directories $suffixes $exclude $directories $csvLogfile $jsonLogfile $xmlLogfile $argv $option[0] $option[1] $option[1] $option[1] $option[1] $option[1] $directories $option $suffixes[] $exclude[] $csvLogfile $jsonLogfile $xmlLogfile $filename $number $number $name $name $namespace $key $name $key $value $key $number $key $default $counts $currentClassComplexity $currentClassLines $currentMethodComplexity $currentMethodLines $currentNumberOfMethods getPublisher $this->counts $filename $this->counts[$key] $this->counts[$key] $this->counts[$key] $this->counts[$key] $this->counts[$key] $this->counts[$key] $this->counts[$key] $this->counts[$key] $this->counts[$key] $this->counts[$key] $this->counts[$key] $this->counts[$key] $this->currentClassComplexity $this->currentClassLines $this->currentNumberOfMethods $this->currentMethodComplexity $this->currentMethodLines $this->counts[$key] $colmap $this->colmap $count[$key] $name $values[] $count['directories'] $count['files'] $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 $count['testClasses'] $count['testMethods'] $count['cloc'] $count['ncloc'] $count['lloc'] $count['llocClasses'] $count['llocFunctions'] $count['llocGlobal'] $count['globalConstantAccesses'] $count['globalVariableAccesses'] $count['superGlobalVariableAccesses'] $count['instanceAttributeAccesses'] $count['staticAttributeAccesses'] $count['instanceMethodCalls'] $count['staticMethodCalls'] $count['abstractClasses'] $count['concreteClasses'] $count['finalClasses'] $count['nonFinalClasses'] $count['nonStaticMethods'] $count['staticMethods'] $count['publicMethods'] $count['protectedMethods'] $count['privateMethods'] $count['namedFunctions'] $count['anonymousFunctions'] $count['globalConstants'] $count['classConstants'] $count['publicClassConstants'] $count['nonPublicClassConstants'] $k $v $key $key $key $key $key $key $default $x $y getDirectories getFiles getLines getCommentLines getNonCommentLines getLogicalLines getClassLines getAverageClassLength getMinimumClassLength getMaximumClassLength getAverageMethodLength getMinimumMethodLength getMaximumMethodLength getAverageMethodsPerClass getMinimumMethodsPerClass getMaximumMethodsPerClass getFunctionLines getAverageFunctionLength getNotInClassesOrFunctions getComplexity getMethodComplexity getAverageComplexityPerLogicalLine getAverageComplexityPerClass getMinimumClassComplexity getMaximumClassComplexity getAverageComplexityPerMethod getMinimumMethodComplexity getMaximumMethodComplexity getGlobalAccesses getGlobalConstantAccesses getGlobalVariableAccesses getSuperGlobalVariableAccesses getAttributeAccesses getNonStaticAttributeAccesses getStaticAttributeAccesses getMethodCalls getNonStaticMethodCalls getStaticMethodCalls getNamespaces getInterfaces getTraits getClasses getAbstractClasses getConcreteClasses getFinalClasses getNonFinalClasses getMethods getNonStaticMethods getStaticMethods getPublicMethods getNonPublicMethods getProtectedMethods getPrivateMethods getFunctions getNamedFunctions getAnonymousFunctions getConstants getGlobalConstants getPublicClassConstants getNonPublicClassConstants getClassConstants getTestClasses getTestMethods toArray getAverage getCount getSum getMaximum getMinimum getValue divide $this->getValue('possible constant accesses', []) $this->getValue('constant', []) $this->counts[$key] $this->counts[$key] $this->counts[$key] $this->counts[$key] $this->counts[$key] $this->counts[$key] $this->counts[$key] $this->counts[$key] $this->counts[$key] $this->getCount('directories') $this->getLines() $this->getLogicalLines() $this->getGlobalConstantAccesses() $this->getNonStaticAttributeAccesses() $this->getNonStaticMethodCalls() $this->getAbstractClasses() $this->getFinalClasses() $this->getNonStaticMethods() $this->getProtectedMethods() $this->getNamedFunctions() $this->getGlobalConstants() $this->getPublicClassConstants() $x phploc-7.0.2/.psalm/config.xml000066400000000000000000000007101376773200700162000ustar00rootroot00000000000000 phploc-7.0.2/ChangeLog.md000066400000000000000000000052041376773200700151730ustar00rootroot00000000000000# Changes in PHPLOC All notable changes in PHPLOC are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles. ## [7.0.2] - 2020-12-07 ### Changed * Changed PHP version constraint in `composer.json` from `^7.3` to `>=7.3` ## [7.0.1] - 2020-08-18 ### Fixed * The `--exclude` CLI option was not handled correctly ## [7.0.0] - 2020-08-13 ### Removed * The `--names` CLI option has been removed; use the `--suffix` CLI option instead * The `--names-exclude` CLI option has been removed; use the `--exclude` CLI option instead ## [6.0.2] - 2020-02-28 ### Fixed * [#207](https://github.com/sebastianbergmann/phploc/issues/207): `TypeError` in `DOMDocument::createElement()` calls ## [6.0.1] - 2020-02-27 ### Fixed * [#205](https://github.com/sebastianbergmann/phploc/pull/205): `TypeError` in `ini_set()` calls ## [6.0.0] - 2020-02-20 ### Removed * This tool is no longer supported on PHP 7.2 ## [5.0.0] - 2019-03-16 ### Fixed * [#182](https://github.com/sebastianbergmann/phploc/pull/182): `"continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"` ### Removed * This tool is no longer supported on PHP 5.6, PHP 7.0, and PHP 7.1 ## [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` * [#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 [7.0.2]: https://github.com/sebastianbergmann/phploc/compare/7.0.1...7.0.2 [7.0.1]: https://github.com/sebastianbergmann/phploc/compare/7.0.0...7.0.1 [7.0.0]: https://github.com/sebastianbergmann/phploc/compare/6.0.2...7.0.0 [6.0.2]: https://github.com/sebastianbergmann/phploc/compare/6.0.1...6.0.2 [6.0.1]: https://github.com/sebastianbergmann/phploc/compare/6.0.0...6.0.1 [6.0.0]: https://github.com/sebastianbergmann/phploc/compare/5.0.0...6.0.0 [5.0.0]: https://github.com/sebastianbergmann/phploc/compare/4.0.1...5.0.0 [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 phploc-7.0.2/LICENSE000066400000000000000000000030051376773200700140240ustar00rootroot00000000000000phploc Copyright (c) 2009-2020, Sebastian Bergmann . 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. phploc-7.0.2/README.md000066400000000000000000000072501376773200700143040ustar00rootroot00000000000000# PHPLOC `phploc` is a tool for quickly measuring the size and analyzing the structure of a PHP project. ## Installation This tool is distributed as a [PHP Archive (PHAR)](https://php.net/phar): ```bash $ wget https://phar.phpunit.de/phploc.phar $ php phploc.phar --version ``` Using [Phive](https://phar.io/) is the recommended way for managing the tool dependencies of your project: ```bash $ phive install phploc $ ./tools/phploc --version ``` **[It is not recommended to use Composer to download and install this tool.](https://twitter.com/s_bergmann/status/999635212723212288)** ## Usage Examples ### Analyse a directory and print the result ``` $ php phploc.phar src phploc 7.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%) ``` phploc-7.0.2/build.xml000066400000000000000000000106151376773200700146450ustar00rootroot00000000000000 phploc-7.0.2/build/000077500000000000000000000000001376773200700141205ustar00rootroot00000000000000phploc-7.0.2/build/phar-autoload.php.in000066400000000000000000000016301376773200700177760ustar00rootroot00000000000000#!/usr/bin/env php run($_SERVER['argv'])); __HALT_COMPILER(); phploc-7.0.2/build/phar-manifest.php000077500000000000000000000013371376773200700173760ustar00rootroot00000000000000#!/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"; } phploc-7.0.2/composer.json000066400000000000000000000020101376773200700155340ustar00rootroot00000000000000{ "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" }, "config": { "platform": { "php": "7.3.0" }, "optimize-autoloader": true, "sort-packages": true }, "require": { "php": ">=7.3", "ext-dom": "*", "ext-json": "*", "sebastian/cli-parser": "^1.0", "sebastian/version": "^3.0", "phpunit/php-file-iterator": "^3.0" }, "autoload": { "classmap": [ "src/" ] }, "bin": [ "phploc" ], "extra": { "branch-alias": { "dev-master": "7.0-dev" } } } phploc-7.0.2/phploc000077500000000000000000000014071376773200700142360ustar00rootroot00000000000000#!/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 ); } exit((new \SebastianBergmann\PHPLOC\Application)->run($_SERVER['argv'])); phploc-7.0.2/phpunit.xml000066400000000000000000000016461376773200700152410ustar00rootroot00000000000000 tests src phploc-7.0.2/src/000077500000000000000000000000001376773200700136105ustar00rootroot00000000000000phploc-7.0.2/src/Analyser.php000066400000000000000000000551671376773200700161150ustar00rootroot00000000000000 * * 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); } } phploc-7.0.2/src/CLI/000077500000000000000000000000001376773200700142175ustar00rootroot00000000000000phploc-7.0.2/src/CLI/Application.php000066400000000000000000000057631376773200700172060ustar00rootroot00000000000000 * * 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] Options for selecting files: --suffix Include files with names ending in in the analysis (default: .php; can be given multiple times) --exclude Exclude files with 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 Write results in CSV format to --log-json Write results in JSON format to --log-xml Write results in XML format to EOT; } } phploc-7.0.2/src/CLI/Arguments.php000066400000000000000000000045011376773200700166750ustar00rootroot00000000000000 * * 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 */ private $directories; /** * @psalm-var list */ private $suffixes; /** * @psalm-var list */ 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 */ public function directories(): array { return $this->directories; } /** * @psalm-return list */ public function suffixes(): array { return $this->suffixes; } /** * @psalm-return list */ 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; } } phploc-7.0.2/src/CLI/ArgumentsBuilder.php000066400000000000000000000054761376773200700202200ustar00rootroot00000000000000 * * 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, ); } } phploc-7.0.2/src/Collector.php000066400000000000000000000144421376773200700162540ustar00rootroot00000000000000 * * 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; } } } phploc-7.0.2/src/Exception/000077500000000000000000000000001376773200700155465ustar00rootroot00000000000000phploc-7.0.2/src/Exception/ArgumentsBuilderException.php000066400000000000000000000006201376773200700234100ustar00rootroot00000000000000 * * 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 { } phploc-7.0.2/src/Exception/Exception.php000066400000000000000000000005331376773200700202160ustar00rootroot00000000000000 * * 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 { } phploc-7.0.2/src/Exception/RuntimeException.php000066400000000000000000000005531376773200700215640ustar00rootroot00000000000000 * * 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 { } phploc-7.0.2/src/Log/000077500000000000000000000000001376773200700143315ustar00rootroot00000000000000phploc-7.0.2/src/Log/Csv.php000066400000000000000000000110461376773200700155770ustar00rootroot00000000000000 * * 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; } } phploc-7.0.2/src/Log/Json.php000066400000000000000000000017031376773200700157540ustar00rootroot00000000000000 * * 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) ); } } phploc-7.0.2/src/Log/Text.php000066400000000000000000000217361376773200700157770ustar00rootroot00000000000000 * * 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'] ); } } } phploc-7.0.2/src/Log/Xml.php000066400000000000000000000024041376773200700156020ustar00rootroot00000000000000 * * 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()); } } phploc-7.0.2/src/Publisher.php000066400000000000000000000322001376773200700162530ustar00rootroot00000000000000 * * 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-7.0.2/tests/000077500000000000000000000000001376773200700141635ustar00rootroot00000000000000phploc-7.0.2/tests/_files/000077500000000000000000000000001376773200700154245ustar00rootroot00000000000000phploc-7.0.2/tests/_files/class_constants.php000066400000000000000000000005451376773200700213420ustar00rootroot00000000000000m(); $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}"; } } phploc-7.0.2/tests/_files/tests.php000066400000000000000000000004511376773200700172770ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\PHPLOC; use const E_ALL; use function error_reporting; use function sprintf; use PHPUnit\Framework\TestCase; /** * @covers \SebastianBergmann\PHPLOC\Analyser */ final class AnalyserTest extends TestCase { /** * @var Analyser */ private $analyser; protected function setUp(): void { $this->analyser = new Analyser; } public function testWithoutTests(): void { $this->assertEqualsWithDelta( [ 'files' => 1, 'loc' => 75, 'lloc' => 24, 'llocClasses' => 22, 'llocFunctions' => 1, 'llocGlobal' => 1, 'cloc' => 7, 'ccn' => 2, 'ccnMethods' => 2, 'interfaces' => 1, 'traits' => 0, 'classes' => 2, 'abstractClasses' => 1, 'concreteClasses' => 1, 'nonFinalClasses' => 1, 'finalClasses' => 0, 'functions' => 2, 'namedFunctions' => 1, 'anonymousFunctions' => 1, 'methods' => 4, 'publicMethods' => 2, 'nonPublicMethods' => 2, 'protectedMethods' => 1, 'privateMethods' => 1, 'nonStaticMethods' => 3, 'staticMethods' => 1, 'constants' => 2, 'classConstants' => 1, 'publicClassConstants' => 1, 'nonPublicClassConstants' => 0, '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, 'averageMethodsPerClass' => 1.33, 'minimumMethodsPerClass' => 0, 'maximumMethodsPerClass' => 4, ], $this->analyser->countFiles( [__DIR__ . '/../_files/source.php'], false ), 0.1 ); } public function testWithTests(): void { $this->assertEqualsWithDelta( [ 'files' => 2, 'loc' => 98, 'lloc' => 24, 'llocClasses' => 22, 'llocFunctions' => 1, 'llocGlobal' => 1, 'cloc' => 11, 'ccn' => 2, 'ccnMethods' => 2, 'interfaces' => 1, 'traits' => 0, 'classes' => 2, 'abstractClasses' => 1, 'concreteClasses' => 1, 'nonFinalClasses' => 1, 'finalClasses' => 0, 'functions' => 2, 'namedFunctions' => 1, 'anonymousFunctions' => 1, 'methods' => 4, 'publicMethods' => 2, 'nonPublicMethods' => 2, 'protectedMethods' => 1, 'privateMethods' => 1, 'nonStaticMethods' => 3, 'staticMethods' => 1, 'constants' => 2, 'publicClassConstants' => 1, 'nonPublicClassConstants' => 0, '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, 'averageMethodsPerClass' => 1, 'minimumMethodsPerClass' => 0, 'maximumMethodsPerClass' => 4, ], $this->analyser->countFiles( [ __DIR__ . '/../_files/source.php', __DIR__ . '/../_files/tests.php', ], true ), 0.1 ); } public function testFilesThatExtendPHPUnitTestCaseAreCountedAsTests(): void { $result = $this->analyser->countFiles( [ __DIR__ . '/../_files/tests.php', ], true ); $this->assertSame(1, $result['testClasses']); } public function testFilesThatExtendPHPUnitTestCaseAreCountedAsTests2(): void { $result = $this->analyser->countFiles( [ __DIR__ . '/../_files/tests_old.php', ], true ); $this->assertSame(1, $result['testClasses']); } public function testFilesThatIndirectlyExtendPHPUnitTestCaseAreCountedAsTests(): void { $result = $this->analyser->countFiles( [ __DIR__ . '/../_files/twoTestsThatIndirectlyExtendOldPHPUnitTestCase.php', ], true ); $this->assertSame(3, $result['testClasses']); } public function testFilesThatIndirectlyExtendPHPUnitTestCaseAreCountedAsTests2(): void { $result = $this->analyser->countFiles( [ __DIR__ . '/../_files/twoTestsThatIndirectlyExtendPHPUnitTestCase.php', ], true ); $this->assertSame(3, $result['testClasses']); } public function testTraitsAreCountedCorrectly(): void { $result = $this->analyser->countFiles( [ __DIR__ . '/../_files/trait.php', ], false ); $this->assertSame(1, $result['traits']); } /** * @ticket 64 */ public function testIssue64IsFixed(): void { $result = $this->analyser->countFiles( [ __DIR__ . '/../_files/issue_62.php', ], false ); $this->assertSame(1, $result['cloc']); } /** * @ticket 112 */ public function testIssue112IsFixed(): void { $result = $this->analyser->countFiles( [ __DIR__ . '/../_files/issue_112.php', ], false ); $this->assertSame(5, $result['loc']); } /** * @ticket 126 * @dataProvider issue126Provider */ public function testIssue126IsFixed($fileNumber, $cloc): void { $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->assertSame($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(): void { error_reporting(E_ALL); $result = $this->analyser->countFiles( [ __DIR__ . '/../_files/issue_138.php', ], false ); $this->assertSame(1, $result['classes']); } /** * @ticket 139 */ public function testIssue139IsFixed(): void { error_reporting(E_ALL); $result = $this->analyser->countFiles( [ __DIR__ . '/../_files/issue_139.php', ], false ); $this->assertSame(1, $result['anonymousFunctions']); } public function testDeclareIsNotLogicalLine(): void { $result = $this->analyser->countFiles([__DIR__ . '/../_files/with_declare.php'], false); $this->assertSame(0, $result['llocGlobal']); } public function testNamespaceIsNotLogicalLine(): void { $result = $this->analyser->countFiles([__DIR__ . '/../_files/with_namespace.php'], false); $this->assertSame(0, $result['llocGlobal']); } public function testImportIsNotLogicalLine(): void { $result = $this->analyser->countFiles([__DIR__ . '/../_files/with_import.php'], false); $this->assertSame(0, $result['llocGlobal']); } public function test_it_makes_a_distinction_between_public_and_non_public_class_constants(): void { $result = $this->analyser->countFiles([__DIR__ . '/../_files/class_constants.php'], false); $this->assertSame(2, $result['publicClassConstants']); $this->assertSame(3, $result['nonPublicClassConstants']); $this->assertSame(5, $result['classConstants']); $this->assertSame(5, $result['constants']); } public function test_it_collects_the_number_of_final_non_final_and_abstract_classes(): void { $result = $this->analyser->countFiles([__DIR__ . '/../_files/classes.php'], false); $this->assertSame(9, $result['classes']); $this->assertSame(2, $result['finalClasses']); $this->assertSame(3, $result['nonFinalClasses']); $this->assertSame(4, $result['abstractClasses']); } public function test_it_makes_a_distinction_between_protected_and_private_methods(): void { $result = $this->analyser->countFiles([__DIR__ . '/../_files/methods.php'], false); $this->assertSame(2, $result['publicMethods']); $this->assertSame(1, $result['protectedMethods']); $this->assertSame(3, $result['privateMethods']); $this->assertSame(6, $result['methods']); } public function test_it_provides_average_minimum_and_maximum_number_of_methods_per_class(): void { $result = $this->analyser->countFiles([__DIR__ . '/../_files/methods_per_class.php'], false); $this->assertSame(2, $result['averageMethodsPerClass']); $this->assertSame(0, $result['minimumMethodsPerClass']); $this->assertSame(4, $result['maximumMethodsPerClass']); } public function test_use_trait_is_not_counted_as_logical_line(): void { $result = $this->analyser->countFiles([__DIR__ . '/../_files/class_using_trait.php'], false); $this->assertSame(1, $result['lloc']); $this->assertSame(1, $result['llocClasses']); } } phploc-7.0.2/tests/unit/Log/000077500000000000000000000000001376773200700156635ustar00rootroot00000000000000phploc-7.0.2/tests/unit/Log/CsvTest.php000066400000000000000000000117131376773200700177720ustar00rootroot00000000000000 * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace SebastianBergmann\PHPLOC; use function count; use function explode; use function ob_end_clean; use function ob_get_clean; use function ob_start; use function trim; use InvalidArgumentException; use PHPUnit\Framework\TestCase; /** * @covers \SebastianBergmann\PHPLOC\Log\Csv */ final class CsvTest 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, 'finalClasses' => 8, 'nonFinalClasses' => 6, 'llocClasses' => 15, 'methods' => 16, 'nonStaticMethods' => 17, 'staticMethods' => 18, 'publicMethods' => 19, 'nonPublicMethods' => 20, 'protectedMethods' => 14, 'privateMethods' => 6, 'methodCcnAvg' => 21, 'functions' => 22, 'namedFunctions' => 23, 'anonymousFunctions' => 24, 'llocFunctions' => 25, 'llocByNof' => 26, 'constants' => 27, 'globalConstants' => 28, 'classConstants' => 29, 'publicClassConstants' => 15, 'nonPublicClassConstants' => 14, 'attributeAccesses' => 30, 'instanceAttributeAccesses' => 31, 'staticAttributeAccesses' => 32, 'methodCalls' => 33, 'instanceMethodCalls' => 34, 'staticMethodCalls' => 35, 'globalAccesses' => 36, 'globalVariableAccesses' => 37, 'superGlobalVariableAccesses' => 38, 'globalConstantAccesses' => 39, 'testClasses' => 40, 'testMethods' => 41, 'classCcnAvg' => 42, 'classLlocAvg' => 43, 'methodLlocAvg' => 44, 'averageMethodsPerClass' => 5, ]; protected function setUp(): void { $this->single = new \SebastianBergmann\PHPLOC\Log\Csv; } public function testPrintedResultContainsHeadings(): void { ob_start(); $this->single->printResult('php://output', $this->sample_row); $output = ob_get_clean(); $this->assertMatchesRegularExpression('#Directories,Files.+$#is', $output, 'Printed result does not contain a heading line'); } public function testPrintedResultContainsData(): void { ob_start(); $this->single->printResult('php://output', $this->sample_row); $output = ob_get_clean(); $this->assertMatchesRegularExpression('#"1","2".+$#is', $output, 'Printed result does not contain a value line'); } public function testPrintedResultContainsEqualNumHeadingsAndValues(): void { 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(): void { 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'); } public function testPrintPartialRow(): void { $this->expectException(InvalidArgumentException::class); $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'); } }