A command line refactoring tool for PHP

Overview

PHP Refactoring Browser

Note: This software is under development and in alpha state. Refactorings
do not contain all necessary pre-conditions and might mess up your code.
Check the diffs carefully before applying the patches.

Build Status

Automatic Refactorings for PHP Code by generating diffs that describe the refactorings steps. To prevent simple mistakes during refactorings, an automated tool is a great.

See a screenshot of extract-method in action.

The library is standing on the shoulder of giants, using multiple existing libraries:

Based on data from these sources the Refactoring Browser consists of two distinct components:

  • Patches allows to build patches based on change operations on a file.
  • Refactoring contains the actual Refactoring domain and adapters to third party libraries.
  • Collections adds some collection semantics on top of PHP arrays. Currently contains a Set type.

Install & Basic Usage

Download PHAR

The refactoring browser is used with:

php refactor.phar <refactoring> <arg1>...<argN>

It outputs a diff to the screen and you can apply it to your code by piping it to patch -p1:

php refactor.phar <refactoring> <arg1>...<argN> | patch -p1

Editor Plugins

There are third-party plugins available for using PHP refactorings within different text editors. These separately maintained projects can be found at the links below:

Why?

Users of PHPStorm (or Netbeans) might wonder why this project exists, all the refactorings are available in this IDE. We feel there are several reasons to have such a tool in PHP natively:

  • We are VIM users and don't want to use an IDE for refactorings. Also we are independent of an IDE and users of any (non PHP Storm) editor can now benefit from the practice of automated refactorings.
  • The non-existence of a simple refactoring tool leads to programmers not refactoring "just to be safe". This hurts long time maintainability of code. Refactoring is one of the most important steps during development and just come easy.
  • Generating patches for refactorings before applying them allows to easily verify the operation yourself or sending it to a colleague.
  • The libraries (see above) to build such a tool are available, so why not do it.
  • The project is an academic of sorts as well, as you can see in the Design Goals we try to be very strict about the Ports and Adapters architecture and a Domain Driven Design.

Refactorings

Extract Method

Extract a range of lines into a new method and call this method from the original location:

php refactor.phar extract-method <file> <line-range> <new-method>

This refactoring automatically detects all necessary inputs and outputs from the function and generates the argument list and return statement accordingly.

Rename Local Variable

Rename a local variable from one to another name:

php refactor.phar rename-local-variable <file> <line> <old-name> <new-name>

Convert Local to Instance Variable

Converts a local variable into an instance variable, creates the property and renames all the occurrences in the selected method to use the instance variable:

php refactor.phar convert-local-to-instance-variable <file> <line> <variable>

Rename Class and Namespaces

Batch Operation to rename classes and namespaces by syncing class-names (IS-state) to filesystem names (SHOULD-state) based on the assumption of PSR-0.

Fix class and namespace names to correspond to the current filesystem layout, given that the project uses PSR-0. This means you can use this tool to rename classes and namespaces by renaming folders and files and then applying the command to fix class and namespaces.

php refactor.phar fix-class-names <dir>

Optimize use statements

Optimizes the use of Fully qualified names in a file so that FQN is imported with "use" at the top of the file and the FQN is replaced with its classname.

All other use statements will be untouched, only new ones will be added.

php refactor.phar optimize-use <file>

Roadmap

Not prioritized.

Integration:

  • Vim Plugin to apply refactorings from within Vim.

List of Refactorings to implement:

  • Extract Method (Prototype Done)
  • Rename Local Variable (Prototype Done)
  • Optimize use statements (Done)
  • Convert Local Variable to Instance Variable (Prototype Done)
  • Rename Class PSR-0 aware (Done)
  • Rename Namespace PSR-0 aware (Done)
  • Convert Magic Value to Constant
  • Rename Method
    • Private Methods Only first
  • Rename Instance Variable
    • Private Variables Only First
  • Extract Interface

Internals

Design Goals

  • Be independent of third-party libraries and any Type Inference Engine (PDepend, PHP Analyzer) via Ports+Adapters
  • Apply Domain-Driven-Design and find suitable Bounded Contexts and Ubiquitous Language within them
  • Avoid primitive obsession by introducing value objects for useful constructs in the domain
Comments
  • [OptimizeUse] Implemented feature optimize use

    [OptimizeUse] Implemented feature optimize use

    Hi there,

    this is my first try at the "optimize use" (-statements) from the roadmap. I had to extend the Namescanner to collect informations about the parent, because I had to differentiate between PhpNames that are in use statements and are just somewhere in the (class-)file. I wasn't quite sure to extend it here, or create another name scanner function or collector. Thats why I added a parent property to the PhpName and had to adjust the tests.

    While contributing some questions came up, that I can't find a guideline for:

    • when do i need to prefix get*** for getters an when not? (PhpClass::getDeclaredNamespaceLine vs PhpName::fullyQualifiedName())
    • do you write "constant" === $variable like in Symfony or does it matter at all?
    • should file and line/line-range in objects of the model domain always be optional in constructor?
    • i had to adjust the behat test after creating it, because of the diff @@ @@ notation. Because of this it's a little bit tricky to write expected patches for behat. Is it possible to work around it a little nicer?
    • is there a guideline for commit messages? (I think i screwed it up)

    Best regards Philipp

    opened by pscheit 10
  • New patch generation system

    New patch generation system

    This PR provides a new mechanism for generating the patches. Please read below

    Benefits

    • More flexibility and resolves the problems I have mentioned before (i.e. fixes the problem I was have working on this https://github.com/QafooLabs/php-refactoring-browser/issues/50)
    • Neater patch generation as all changes are taken into account at the point of creating the patch.
    • Allows more complex refactorings as it would now be possible to re-analyse the partially refactored code for further refactoring rather than relying on code analysis just from the original file content. I think this will be very useful as the refactorings are added to and developped.

    Implementation

    The patch is generated by phpspec/php-diff which is the library phpspec uses to produce diffs https://github.com/phpspec/php-diff

    This is done via a patch building library which I have created for this purpose and put into a seperate repository as I it could be useful in other project also. https://github.com/tomphp/PatchBuilder

    Testing

    One thing I which I should say is that I have had to modify the behat features to get it to pass, the reason for this is that behat is testing the actual patch output which had been changed (and optimised) in this version.

    I think a better solution would be to test the results of the patches, i.e. generated the patches and hand them to the patch command then check the result. I'm not sure however if this would be possible using the virtual file system and therefore make require using the real file system.

    While I'm 90% sure everything that I have done is correct, it might first be work updating the test suite with the new method i just mentioned against the existing code then running this pr against that test suite. Thoughts?

    Tidying Up

    This PR currently has all the left over classes from the old patch system lying around, I will tidy this up before expecting a merge.

    What next?

    I will compile and personally use this modded version for a while and see that it's working properly. If it is I think it would be great if we could go ahead with this version as it will allow progress with feature development.

    opened by tomphp 6
  • Add autoreading of the refactored code

    Add autoreading of the refactored code

    Got the the buffer reloading. Next I guess it's to try and get it working without going to the console and requesting pressing enter.

    I've also just realised there's a bug where it doesn't work properly if the file being refactorred isn't in the cwd, I'll see if I can work this out tomorrow. Maybe need to work out -p command for patch.

    opened by tomphp 6
  • Method renaming is not supported

    Method renaming is not supported

    Hi,

    I am using CodeLite as my PHP IDE. There is one limitation in that IDE and that is Method renaming is not supported.

    I've raised that issue there. Following is the reference link:

    https://github.com/eranif/codelite/issues/1725

    When can we expect Method renaming feature in this library

    opened by zestllankesh 4
  • What is current state of this package?

    What is current state of this package?

    Packages looks like abandoned, I guess because of TokenReflection - yep, I got to replace it too in ApiGen. Is that so?

    I wonder, what do you instead? How were you satisfied with this solution?

    I'm into building such refactor tool so I look for experience.

    opened by TomasVotruba 4
  • Makes (not affected) absolute use-statements relative in fix-class-names

    Makes (not affected) absolute use-statements relative in fix-class-names

    One of the recent changes introduced that fix-class-names changes use statments to be relative even if the were validly absolute before, see http://files.schlitt.info/tmp/diff_issues.patch.

    To reproduce this diff do the following:

    1. Checkout https://github.com/Qafoo/changetrack revision 60a94df
    2. Move src/main/Qafoo/ChangeTrack/Analyzer/Vcs/GitCheckout.php -> src/main/Qafoo/ChangeTrack/Analyzer/Checkout/GitCheckout.php
    3. Execute refactor fix-class-names src/ test/ > diff_issues.patch

    Btw. the intended changes do not occur in the diff at all.

    wontfix 
    opened by tobyS 4
  • Creates many empty diffs

    Creates many empty diffs

    One of the recent changes introduced that refactorings might contain many empty diffs in addition to the relevant ones, see http://files.schlitt.info/tmp/diff_issues.patch.

    To reproduce this diff do the following:

    1. Checkout https://github.com/Qafoo/changetrack revision 60a94df5c2d761f6af6ceb3ae9e0dd979f17a40a
    2. Move src/main/Qafoo/ChangeTrack/Analyzer/Vcs/GitCheckout.php -> src/main/Qafoo/ChangeTrack/Analyzer/Checkout/GitCheckout.php
    3. Execute refactor fix-class-names src/ test/ > diff_issues.patch

    Btw. the intended changes do not occur in the diff at all.

    bug 
    opened by tobyS 3
  • Basic vim bindings

    Basic vim bindings

    This is not meant to be a complete implementation of VIM bindings, I just did this so I could start using php-refactor-browser in VIM right now and I thought I'd share it in case others want to try too.

    opened by tomphp 3
  • Lock dependencies and fix tests

    Lock dependencies and fix tests

    This PR does the following:

    • Requires PHPUnit rather than assuming it is installed globally
    • Locks Symfony component versions to 2.*
    • Locks Behat to version 2.*
    • Updates Behat's FeatureContext to use local PHPUnit assert function
    • Locks tomphp/patch-builder to version 0.1.* (I'm planning some work on this which may cause BC breaks locking will avoid being affected).
    opened by tomphp 2
  • Extract method works properly with code indented more than one level

    Extract method works properly with code indented more than one level

    Extract method was messing up the extracted method if the code being extracted was indented more than 4 spaces.

    Also the method call to the extracted method was not indented correctly.

    This PR fixes both these issues.

    Unit tests & acceptance tests are included.

    PS: For some reason 2 scenarios are failing the the Fix Class Names feature but there were failing before I started working so I'm assuming that they either are currently broken in the repo or something in my environment?

    opened by tomphp 2
  • optimize-use: Declared class imported

    optimize-use: Declared class imported

    Using the optimize-use command on test/features/bootstrap/FeatureContext.php (known project) yields an import for the class that is declared in the file:

    $ refactor optimize-use test/features/bootstrap/FeatureContext.php 
    --- a/test/features/bootstrap/FeatureContext.php
    +++ b/test/features/bootstrap/FeatureContext.php
    @@ -10,15 +10,26 @@
     use Qafoo\ChangeTrack\Analyzer;
     use Qafoo\ChangeTrack\Calculator;
     use Qafoo\ChangeTrack\Change;
    +use FeatureContext;
    
    …
    
    -class FeatureContext extends BehatContext
    +class FeatureContext extends BehatContext
    
    …
    
    opened by tobyS 2
  • use kdambekalns php-token-reflection fork

    use kdambekalns php-token-reflection fork

    made this fork a while ago and the refactor.phar works afaik. won't be working on this any more but thought it might be useful for others.

    This PR looks much more involved and developed but I haven't tested it out

    opened by MarTango 1
  • Unset operations are not seen as changing a value

    Unset operations are not seen as changing a value

        function test()
        {
            $userHelper = [1,2];
            unset($options[0]);
        }
    

    Refactoring the secound line in the function will fail to take account for the unsetting changing $options and it needing to be retuned or passed by reference.

        function test()
        {
            $options = [1,2];
            $this->asd($options);
        }
    
        private function asd($options)
        {
            unset($options[0]);
        }
    

    expected

        function test()
        {
            $options = [1,2];
            $options = $this->asd($options);
        }
    
        private function asd($options)
        {
            unset($options[0]);
            return $options;
        }
    
    opened by AJenbo 0
  • Allow stdin input for single file refactors

    Allow stdin input for single file refactors

    Allowing stdin input has many uses and is, in my opinion essential.

    I'm not familiar with the codebase, but I came up with these changes to support stdin.

    Example of use: $ cat home.php | php refactor.phar extract-method - 7-7 myNewFunction (obviously this isn't a great example of a use case)

    Replacing the filename parameter with - will tell refactor.phar to use stdin as the file contents instead of a specific file.

    As most commands have a dependency on the File class, it will create a tmpfile() with the stdin contents, and then create a File object from the temporary file. I've added a static File::createFromContents() function to facilitate this.

    Use cases are numerous, but my specific use case/reason for implementation is for the vim-php-refactoring plugin (i've also forked to support this change). Which has multiple restrictions thrust upon it due to php-refactoring-browser not supporting stdin input.

    Example: :%!php refactor.phar extract-method - 7-7 myNewFunction | patch --silent --ouput=- --dir="/tmp"

    This allows on-the-fly refactoring of modified vim buffers, without worrying about loosing unsaved buffer changes, or directly modifying and having the reload the file on disk. It makes the whole experience much more seamless.

    opened by LeighBicknell 0
  • Rename local variable only works within classes.

    Rename local variable only works within classes.

    I realise that this is designed primarily for use within classes however sometimes you can't/don't have 100% of your functions as methods in a class, when working in Wordpress for example.

    Having the rename-local-variable functionality working for standard global space functions as well as methods would be a nice feature. Currently it returns an error:

    $ php refactor.phar rename-local-variable test.php 136 oldname newname
    
    [QafooLabs\Refactoring\Domain\Model\RefactoringException]  
      The range 136-136 is not inside one single method.         
    
    rename-local-variable file line name new-name
    
    opened by LeighBicknell 2
  • Creating setters and getters

    Creating setters and getters

    This is a task that is quite annoying and that you have to do quite often:

    The syntax could be:

    php refactor.phar create-setter <file> <line> php refactor.phar create-getter <file> <line>

    and maybe (but not absolutely necessary) :

    php refactor.phar create-getter-setter <file> <line>

    opened by edi9999 0
Releases(v0.1)
Instant Upgrades and Instant Refactoring of any PHP 5.3+ code

Rector - Speedup Your PHP Development Rector helps you with 2 areas - major code changes and in daily work. Do you have a legacy code base? Do you wan

RectorPHP 6.5k Jan 8, 2023
A collection of tools to help with PHP command line utilities

PHP Command Line Tools A collection of functions and classes to assist with command line development. Requirements PHP >= 5.3 Suggested PHP extensions

WP-CLI 651 Dec 21, 2022
Analyze PHP code with one command

PHPQA Analyze PHP code with one command. Requirements PHP >= 5.4.0 xsl extension for HTML reports Why? Every analyzer has different arguments and opti

edgedesign/phpqa 542 Dec 24, 2022
PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD. PHPMD can be seen as an user friendly frontend application for the raw metrics stream measured by PHP Depend.

PHPMD PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD. PHPMD can be seen as an user friendly

PHP Mess Detector 2.1k Jan 8, 2023
PHP Architecture Tester - Easy to use architectural testing tool for PHP :heavy_check_mark:

Easy to use architecture testing tool for PHP Introduction ?? PHP Architecture Tester is a static analysis tool to verify architectural requirements.

Carlos A Sastre 765 Dec 30, 2022
A tool to automatically fix PHP Coding Standards issues

PHP Coding Standards Fixer The PHP Coding Standards Fixer (PHP CS Fixer) tool fixes your code to follow standards; whether you want to follow PHP codi

null 11.6k Jan 3, 2023
PHP Static Analysis Tool - discover bugs in your code without running it!

PHPStan - PHP Static Analysis Tool PHPStan focuses on finding errors in your code without actually running it. It catches whole classes of bugs even b

PHPStan 11.6k Dec 30, 2022
A PHP code-quality tool

GrumPHP Sick and tired of defending code quality over and over again? GrumPHP will do it for you! This composer plugin will register some git hooks in

PHPro 3.9k Jan 1, 2023
Beautiful and understandable static analysis tool for PHP

PhpMetrics PhpMetrics provides metrics about PHP project and classes, with beautiful and readable HTML report. Documentation | Twitter | Contributing

PhpMetrics 2.3k Dec 22, 2022
A tool for quickly measuring the size of a PHP project.

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 Ar

Sebastian Bergmann 2.3k Jan 4, 2023
A static php code analysis tool using the Graph Theory

Mondrian Ok guyz, you have a master degree in Graph Theory, you follow Law of Demeter and you live on S.O.L.I.D principles ? Let's have some Fun ! (^ω

Florent Genette 391 Nov 30, 2022
PHPCheckstyle is an open-source tool that helps PHP programmers adhere to certain coding conventions.

PHPCheckstyle Overview PHPCheckstyle is an open-source tool that helps PHP programmers adhere to certain coding conventions. The tools checks the inpu

PHPCheckstyle 157 Dec 5, 2022
A static analysis tool for finding errors in PHP applications

Psalm Psalm is a static analysis tool for finding errors in PHP applications. Installation To get started, check out the installation guide. Live Demo

Vimeo 5k Jan 2, 2023
A web tool to explore the ASTs generated by PHP-Parser.

phpast.com A web tool to explore the ASTs generated by PHP-Parser. About This web tool provides a GUI for exploring the AST of your PHP code. You can

Ryan Chandler 23 Nov 29, 2022
Deptrac is a static code analysis tool for PHP that helps you communicate, visualize and enforce architectural decisions in your projects

Deptrac is a static code analysis tool for PHP that helps you communicate, visualize and enforce architectural decisions in your projects. You can freely define your architectural layers over classes and which rules should apply to them.

QOSSMIC GmbH 2.2k Dec 30, 2022
A tool to automatically fix PHP Coding Standards issues by Dragon Code.

A tool to automatically fix PHP Coding Standards issues by Dragon Code.

The Dragon Code 24 Aug 27, 2022
Tool helping us to analyze software projects

Qafoo Quality Analyzer This software is a tool to visualize metrics and source code. We use this software for Code Reviews together with our customers

Qafoo GmbH 494 Dec 29, 2022
Baseline tool for PHP_CodeSniffer

PHP_CodeSniffer Baseliner This tool enables you to integrate PHP_CodeSniffer into an existing project by automatically adding phpcs:ignore and phpcs:d

ISAAC 13 Nov 26, 2022
All In 1 Spam Tool For Termux Users Subscribe Us (Noob Hackers) some shit heads are trying to abuse this script so don't worry about them ...let them hallucinate ...but you are free to use this script

ABOUT TOOL : SPAMX is a all in one Bombing+Spam tool from this tool you can send anonymous messages to your target without showing your real number an

N17R0 449 Jan 7, 2023