churn-php is a package that helps you identify php files in your project that could be good candidates for refactoring

Overview

churn-php

Helps discover good candidates for refactoring.

Build Status codecov Scrutinizer Code Quality Code Climate Packagist Packagist Packagist Donate

Table of Contents

What is it?

churn-php is a package that helps you identify php files in your project that could be good candidates for refactoring. It examines each PHP file in the path it is provided and:

  • Checks how many commits it has.
  • Calculates the cyclomatic complexity.
  • Creates a score based on these two values.

The results are displayed in a table:

A file that changes a lot and has a high complexity might be a better candidate for refactoring than a file that doesn't change a lot and has a low complexity.

churn-php only assists the developer to identify files for refactoring. It's best to use the results in addition to your own judgment to decide which files you may want to refactor.

Compatibility

  • PHP 7.1+

If you want to install churn-php in Symfony project, your Symfony components version must be 3.4 or higher.

How to Install?

Install via Composer:

composer require bmitch/churn-php --dev

You can also install churn-php with Phive:

phive install churn

How to Use?

vendor/bin/churn run 
   
     ...
vendor/bin/churn run src
vendor/bin/churn run src tests

   

You can also use churn-php via Docker:

docker run --rm -ti -v $PWD:/app dockerizedphp/churn run src

How to Configure?

You may add an optional churn.yml file which can be used to configure churn-php. The location of the churn.yml file can be customized using these commands:

vendor/bin/churn run --configuration=my-config.yml ">
# Default: "churn.yml" 
vendor/bin/churn run --configuration=config-dir/ 
     
      
vendor/bin/churn run --configuration=my-config.yml 
      

      
     

A sample churn.yml file looks like:

# The maximum number of files to display in the results table.
# Default: 10
filesToShow: 10

# The minimum score a file need to display in the results table.
# Disabled if null.
# Default: 0.1
minScoreToShow: 0

# The command returns an 1 exit code if the highest score is greater than the threshold.
# Disabled if null.
# Default: null
maxScoreThreshold: 0.9

# The number of parallel jobs to use when processing files.
# Default: 10
parallelJobs: 10

# How far back in the VCS history to count the number of commits to a file
# Can be a human readable date like 'One week ago' or a date like '2017-07-12'
# Default: '10 Years ago'
commitsSince: One year ago

# Files to ignore when processing. The full path to the file relative to the root of your project is required.
# Also supports regular expressions.
# Default: All PHP files in the path provided to churn-php are processed.
filesToIgnore:
 - src/Commands/ChurnCommand.php
 - src/Results/ResultsParser.php
 - src/Foo/Ba*

# File extensions to use when processing.
# Default: php
fileExtensions:
 - php
 - inc

# This list is used only if there is no argument when running churn.
# Default: 
   
directoriesToScan:
 - src
 - tests/

# List of user-defined hooks.
# They can be referenced by their full qualified class name if churn has access to the autoloader.
# Otherwise the file path can be used as well.
# See below the section about hooks for more details.
# Default: 
   
hooks:
 - Namespace\MyHook
 - path/to/my-hook.php

# The version control system used for your project.
# Accepted values: fossil, git, mercurial, subversion, none
# Default: git
vcs: git

# The path of the cache file. It doesn't need to exist before running churn.
# Disabled if null.
# Default: null
cachePath: .churn.cache

If a churn.yml file is omitted or an individual setting is omitted the default values above will be used.

Output formats

You can configure churn to output the result in different formats. The available formats are:

  • csv
  • json
  • text (default)

To use a different format use --format option. Example command for json:

vendor/bin/churn run --format json

Hooks

The hooks configuration allows you to customize churn.

A user-defined hook must implement at least one of the following interfaces:

Similar Packages

Contact

Questions, comments, feedback? @bmitch2112

Contributing

  • Please run composer test on PHP 7.1 and ensure it passes.
  • If you don't have access to PHP 7.1 please make sure that CI build passes when you make pull request. If you are unable to get it to pass in the pull request please ping me and I can help.
  • Please see CONTRIBUTING.md

License

The MIT License (MIT). Please see License File for more information.

Comments
  • [WIP] (Auto)generate a .phar

    [WIP] (Auto)generate a .phar

    See #126. I've got this working with some minor adaptations.

    I'm using https://github.com/box-project/box2 If you follow the installation instructions over there, you can finally run box build and this will generate churn.phar, which can be used in the same way as churn.

    Apparently it can even be incorporated into the release cycle on Travis: https://github.com/FriendsOfPHP/pickle/blob/master/.travis.yml, meaning we can have a fresh .phar file generated for each GitHub release. I have no experience with this, but I'll try to figure it out.

    opened by matthiasnoback 9
  • Doesn't work in windows.

    Doesn't work in windows.

    Because of this line:

    https://github.com/bmitch/churn-php/blob/master/src/Factories/ProcessFactory.php#L35

    Is there another command that will do the same thing that works in Windows and Unix?

    enhancement help wanted 
    opened by bmitch 9
  • No results - script hangs forever

    No results - script hangs forever

    I tried today to test out churn-php in one of my projects, but when executing vendor/bin/churn run src the script just runs forever (one CPU is at 100% during that time) and never returns a result. I tried waiting one hour, but even then it is not finished, so I suspect this is a bug.

    My used software and project details:

    • PHP 7.2.1
    • churn-php 0.4.1
    • 1600 commits in the project
    • 1715 files and 320 directories in /src

    Not sure if maybe PHP 7.2 is the reason for these problems?

    opened by iquito 8
  • CyclomaticComplexityAssessor - Improve by using something like `nikic/PHP-Parser`

    CyclomaticComplexityAssessor - Improve by using something like `nikic/PHP-Parser`

    The score is calculated by using regular expressions which leads to errors.

    Example of a PHP file containing only a comment:

    <?php
    // if ( if ( if (
    

    In this example the score is 3 whereas it should be 1.

    This kind of error could be avoided by using PHP-Parser.

    enhancement 
    opened by villfa 8
  • Expected a value greater than 0. Got: 0

    Expected a value greater than 0. Got: 0

    Installed the package, my code is in src folder. Executed the command

    bin/churn run src
    

    and got the error

    Expected a value greater than 0. Got: 0
    

    What is wrong?

    enhancement 
    opened by luchianenco 7
  • Suggestion to change the scoring

    Suggestion to change the scoring

    Thanks for a nice tool!

    The way I understand it (and the way it's described in this article: https://www.sandimetz.com/blog/2017/9/13/breaking-up-the-behemoth), we should consider to refactor classes that are high on high on both complexity and times changed. Otherwise, we would start refactoring complex classes that change almost never (which is a waste of effort) or we would start refactoring simple classes that change often (which also makes no sense, since it's very easy to make the change, so it doesn't cost us much).

    What do you think?

    opened by matthiasnoback 7
  • Improved scoring

    Improved scoring

    Hi everyone,

    I picked up the work based on #97. I came up with a calculation that to me makes a lot of sense. See Result::getScore() and the comments inside it.

    By normalizing the scores you basically end up with coordinates in a square of 1 by 1. The scores are based on the distance of each class to the top-right corner (the "worst" classes). In the green area, the score will be between 1 and 0. In the blue area, the score will be below 0.

    diagram

    I also added a CLI option to generate JSON output, since I'm working on some tool to generate a nice diagram based on the output. Right now it looks something like this: screen shot 2017-10-04 at 16 21 06

    I'm not quite ready to open-source that tool (since it's quite crappy atm ;)). But it would help to know if you'd be okay merging my changes in. I do realize that there is at least one breaking API change (you have to provide arguments to Result::getScore() now). And the overall behavior has changed, meaning that values like "minimum score" have to be revised by users. However, I think it's for the better. A minimum score of 0 basically cuts of any class that is below the line in the diagram, so it's okay to ignore them. One thing we could do is add a sanity check and warn the user that the minimum score provided should be lower than 1.

    I'd be happy to hear your thoughts and please let me know if anything is not up to your standard.

    opened by matthiasnoback 6
  • Enhance readme / documentation

    Enhance readme / documentation

    I'm open to reviews of the readme if anyone has any suggestions.

    • Any information missing or instructions missing.
    • Better layout/design/look.
    • Anything else you'd like to see in the readme.
    hacktoberfest 
    opened by bmitch 6
  • Enhancement: Update phpunit/phpunit

    Enhancement: Update phpunit/phpunit

    This PR

    • [x] updates phpunit/phpunit
    • [x] uses an actual version constraint for mockery/mockery
    • [x] fixes risky tests by adding to assertion count from Mockery

    💁‍♂️ For reference, see https://github.com/sebastianbergmann/phpunit/compare/5.7.27...6.5.13.

    opened by localheinz 5
  • Fix composer scripts for windows

    Fix composer scripts for windows

    On Windows the command composer test produces the following error:

    'vendor' is not recognized as an internal or external command
    

    Removing vendor/bin/ from the commands fixes this problem.

    I also noticed some namespaces were wrong in the unit tests files so I fixed them.

    opened by villfa 5
  • Unable to install for symfony 3.1.10 project

    Unable to install for symfony 3.1.10 project

    When I run composer require bmitch/churn-php --dev, I receive next errors

    vagrant@jessie:/var/www/core2$ composer require bmitch/churn-php
    Using version ^0.3.1 for bmitch/churn-php
    ./composer.json has been updated
    Loading composer repositories with package information
    Updating dependencies (including require-dev)
    Your requirements could not be resolved to an installable set of packages.
    
      Problem 1
        - Installation request for bmitch/churn-php ^0.3.1 -> satisfiable by bmitch/churn-php[0.3.1].
        - Conclusion: remove symfony/symfony v3.1.10
        - Conclusion: don't install symfony/symfony v3.1.10
        - bmitch/churn-php 0.3.1 requires symfony/process ^3.2 -> satisfiable by symfony/process[3.2.x-dev, 3.3.x-dev, 3.4.x-dev, v3.2.0, v3.2.0-BETA1, v3.2.0-RC1, v3.2.0-RC2, v3.2.1, v3.2.10, v3.2.11, v3.2.12, v3.2.13, v3.2.2, v3.2.3, v3.2.4, v3.2.5, v3.2.6, v3.2.7, v3.2.8, v3.2.9, v3.3.0, v3.3.0-BETA1, v3.3.0-RC1, v3.3.1, v3.3.10, v3.3.2, v3.3.3, v3.3.4, v3.3.5, v3.3.6, v3.3.7, v3.3.8, v3.3.9].
        - don't install symfony/process 3.2.x-dev|don't install symfony/symfony v3.1.10
        - don't install symfony/process 3.3.x-dev|don't install symfony/symfony v3.1.10
        - don't install symfony/process 3.4.x-dev|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.2.0|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.2.0-BETA1|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.2.0-RC1|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.2.0-RC2|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.2.1|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.2.10|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.2.11|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.2.12|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.2.13|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.2.2|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.2.3|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.2.4|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.2.5|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.2.6|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.2.7|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.2.8|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.2.9|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.3.0|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.3.0-BETA1|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.3.0-RC1|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.3.1|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.3.10|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.3.2|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.3.3|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.3.4|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.3.5|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.3.6|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.3.7|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.3.8|don't install symfony/symfony v3.1.10
        - don't install symfony/process v3.3.9|don't install symfony/symfony v3.1.10
        - Installation request for symfony/symfony (locked at v3.1.10, required as ~3.1.8) -> satisfiable by symfony/symfony[v3.1.10].
    
    Installation failed, reverting ./composer.json to its original content.
    

    My composer.json:

    {
        "name": "",
        "license": "proprietary",
        "type": "project",
        "description": "",
        "autoload": {
            "psr-4": {
                "Sio\\": "src/Sio/",
                "AppBundle\\": "src/AppBundle/"
            },
            "classmap": [
                "app/AppKernel.php",
                "app/AppCache.php"
            ]
        },
        "require": {
            "php": ">=5.6",
            "symfony/symfony": "~3.1.8",
            "twig/twig": "~1.31",
            "symfony/monolog-bundle": "~3.0",
            "sensio/framework-extra-bundle": "~3.0",
            "sensio/distribution-bundle": "~5.0",
            "wikimedia/composer-merge-plugin": "~1.3",
            "guzzlehttp/guzzle": "~6.2",
            "alcaeus/mongo-php-adapter": "~1.0",
            "doctrine/mongodb-odm-bundle": "~3.2",
            "gedmo/doctrine-extensions": "~2.4",
            "snc/redis-bundle": "^2.0.1",
            "predis/predis": "~1.1",
            "composer/semver": "~1.4",
            "incenteev/composer-parameter-handler": "^2.0",
            "friendsofsymfony/rest-bundle": "~2.0",
            "jms/serializer-bundle": "~1.1",
            "nelmio/api-doc-bundle": "~2.10",
            "memio/memio": "^1.1",
            "marcj/topsort": "~1.0",
            "php-http/guzzle6-adapter": "~1.1",
            "ruflin/elastica": "~5.1",
            "oneup/uploader-bundle": "~1.7",
            "league/flysystem": "~1.0",
            "league/flysystem-aws-s3-v3": "^1.0",
            "ramsey/uuid": "~3.5",
            "swiftmailer/swiftmailer": "~5.4",
            "aws/aws-sdk-php": "~3.18",
            "myclabs/php-enum": "~1.2",
            "mikehaertl/phpwkhtmltopdf": "~2.2",
            "duccio/apns-php": "~1.0",
            "ddeboer/data-import": "~0.2",
            "krakjoe/pthreads-polyfill": "dev-master",
            "nilz/money": "~1.1",
            "james-heinrich/getid3": "^1.9",
            "rodneyrehm/plist": "~2.0",
            "ddeboer/imap": "^0.5.2",
            "phpoffice/phpexcel": "^1.8",
            "giggsey/libphonenumber-for-php": "^8.8",
            "ocramius/proxy-manager": "^2.1",
            "league/flysystem-webdav": "^1.0",
            "league/flysystem-cached-adapter": "^1.0"
        },
        "require-dev": {
            "sensio/generator-bundle": "^3.0",
            "symfony/phpunit-bridge": "^3.0",
            "phpunit/phpunit": "~5.6",
            "nelmio/alice": "~2.2",
            "phpspec/prophecy": "~1.6",
            "fzaninotto/faker": "~1.6",
            "composer/composer": "~1.3",
            "mockery/mockery": "^0.9.7",
            "diablomedia/phpunit-pretty-printer": "^1.0",
            "doctrine/doctrine-fixtures-bundle": "^2.3"
        },
        "provide": {
            "ext-mongo": "1.6.0",
            "ext-pthreads": "2.0.0"
        },
        "minimum-stability": "dev",
        "prefer-stable": true,
        "scripts": {
            "symfony-scripts": [
                "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
                "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache",
                "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile"
            ],
            "reload-bundle-integration": [
                "Sio\\Dynamic\\SetupBundle\\Handler\\DynamicBundleIntegrationHandler::buildKernel",
                "Sio\\Dynamic\\SetupBundle\\Handler\\DynamicBundleIntegrationHandler::generateModels"
            ],
            "post-install-cmd": [
                "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters",
                "@reload-bundle-integration",
                "@symfony-scripts"
            ],
            "post-update-cmd": [
                "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters",
                "@reload-bundle-integration",
                "@symfony-scripts"
            ]
        },
        "extra": {
            "merge-plugin": {
                "include": [
                    "var/installed/installed.composer.json"
                ]
            },
            "symfony-app-dir": "app",
            "symfony-bin-dir": "bin",
            "symfony-var-dir": "var",
            "symfony-web-dir": "web",
            "symfony-tests-dir": "tests",
            "symfony-assets-install": "relative",
            "incenteev-parameters": {
                "file": "app/config/parameters.yml"
            }
        }
    }
    
    opened by metamaker 5
  • Negative Scores?

    Negative Scores?

    I was confused why I was not getting the full filesToShow when minScoreToShow was 0. It turns out some scores are coming back negative: | Times Changed | Complexity | Score | |---------------|------------|--------| | 45 | 1068 | 1 | | 40 | 792 | 0.719 | | 26 | 786 | 0.502 | | 38 | 418 | 0.372 | | 25 | 591 | 0.37 | | 30 | 378 | 0.273 | | 33 | 290 | 0.224 | | 18 | 457 | 0.171 | | 21 | 387 | 0.169 | | 11 | 697 | 0.168 | | 21 | 354 | 0.145 | | 14 | 406 | 0.073 | | 15 | 323 | 0.035 | | 17 | 281 | 0.036 | | 19 | 245 | 0.037 | | 18 | 229 | 0.011 | | 20 | 191 | 0.009 | | 10 | 377 | -0.012 | | 15 | 250 | -0.015 | | 16 | 145 | -0.078 |

    I know score is a somewhat-contrived calculation based on the actual value columns... but how does a negative make sense?

    opened by MGatner 3
  • Feature: Allow to use cognitive instead of cyclomatic complexity

    Feature: Allow to use cognitive instead of cyclomatic complexity

    Cognitive complexity seems to have some advantages over cyclomatic complexity, for the understandability of code.

    For example, a long but simple switch/case block has a very high cyclomatic complexity but a low cognitive complexity. Here is a good description of the differences: https://docs.codeclimate.com/docs/cognitive-complexity

    Maybe the analyzer from https://github.com/Rarst/phpcs-cognitive-complexity can be used to add this alternative metric?

    enhancement 
    opened by haraldreingruber 0
Releases(1.7.1)
Owner
Bill Mitchell
Backend developer. Passionate about coding standards, testing, object oriented design and building great software with others.
Bill Mitchell
salah eddine bendyab 18 Aug 17, 2021
A PHP web interface for scanning ISBN book codes, identify books with Antolin reading promotion offer

Ein PHP-Webinterface zum Scannen von ISBN-Buchcodes, identifiziere Bücher mit Antolin-Leseförderungs-Angebot. Einfache Installation. Für Mitarbeiter*innen in Schulbüchereien.

null 2 May 20, 2022
PHP examples - Refactoring by Martin Fowler

Refatoração - segunda edição - Exemplos em PHP https://www.youtube.com/watch?v=TBHehDRuVCs Prefácio: Case de refatoração x entregas e prazos O que é r

Eduardo Lourenço 3 Jul 20, 2022
A good plugin to play a sound when the player hits the enemy's head

HeadshotSound A good plugin to play a sound when the player hits the enemy's head. How to use Hit the player with a snowball, egg and bow in the head

Laith Youtuber 6 Nov 3, 2022
Michael Pratt 307 Dec 23, 2022
Greyhole uses Samba to create a storage pool of all your available hard drives, and allows you to create redundant copies of the files you store.

Greyhole Greyhole is an application that uses Samba to create a storage pool of all your available hard drives (whatever their size, however they're c

Guillaume Boudreau 245 Dec 18, 2022
A Laravel package which helps you to flush sessions with an artisan command.

A simple laravel Package to flush sessions via artisan command. Sometimes we store data on sessions such as cart data or maybe any information regardi

Erfan Ahmed Siam 5 Jun 1, 2023
A PHP CLI application that helps you organize your aliases.

Alias CLI A PHP CLI application that helps you organize your aliases. Installation composer require --dev alexgaal/alias After installing Alias CLI we

Alexander Gaal 7 Aug 12, 2022
EBook-Apps - The eBook Apps is a web application that helps you browse ebooks from anywhere using your smartphone and laptop.

⚡️ eBook Apps The eBook Apps is a web application that helps you browse ebooks from anywhere using your smartphone and laptop. ?? Getting Started To s

Ahmad Fauzy 32 Nov 14, 2022
The Ravioli WooCommerce plugin helps you ship your order with Ravioli.

=== Ravioli for WooCommerce === Contributors: canolcer Tags: ravioli, ecommerce, shipping Requires at least: 5.0 Tested up to: 6.0.1 Stable tag: trunk

Ravioli 2 Nov 7, 2022
This is a Native PHP MVC. If you will build your own PHP project in MVC with router, you can clone this ready to use MVC pattern repo.

Welcome to PHP-Native-MVC-Pattern ?? If you will build your own PHP project in MVC with router, you can clone this ready to use MVC pattern repo. Work

null 2 Jun 6, 2022
Orangescrum is a simple yet powerful free and open source project management software that helps team to organize their tasks, projects and deliver more.

Free, open source Project Management software Introduction Orangescrum is the simple yet powerful free and open source project management software tha

Orangescrum 110 Dec 30, 2022
Roach-example-project - Example project to demonstrate how to use RoachPHP in a Laravel project.

Example repository to illustrate how to use roach-php/laravel in a Laravel app. Check app/Spiders/FussballdatenSpider.php for an example spider that c

Kai Sassnowski 11 Dec 15, 2022
A simple and easy-to-use enumeration extension package to help you manage enumerations in your project more conveniently

A simple and easy-to-use enumeration extension package to help you manage enumerations in your project more conveniently

null 3 Jul 29, 2022
Utility that helps you switch git configurations with ease.

git-profile Utility that helps you switch git configurations with ease Preface It is possible that you have multiple git configurations. For example:

Zeeshan Ahmad 240 Jul 18, 2022
Fly50W is a new language which helps you build simple apps using more than 500k lines of code easily.

Fly50W is a new language which helps you build simple apps using more than 500k lines of code easily. Installation

null 4 Jun 22, 2022