Qafoo GmbH - passion for software quality ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :Author: Benjamin Eberlei :Date: Mon, 08 Apr 2013 09:56:18 +0200 :Revision: 8 :Copyright: All rights reserved ===================================== PHP Refactoring Browser Alpha Release ===================================== :Keywords: php, refactoring, tool, quality, testing, ide :Description: Constant refactoring is a cornerstone of TDD and an important technique to learn and apply during development. With the PHP Refactoring Browser we are releasing a tool that allows to automate common refactorings with a command line tool. :Abstract: Without continuous refactoring, code maintainability and extensibility will start to decrease fast, even if it has tests. Until now, only IDEs contained functionality to perform automated refactorings. And then even only PHPStorm contains the most important refactorings such as "extract method". Today we release the `PHP Refactoring Browser `_, a refactoring tool written completely in PHP. Without continuous refactoring, code maintainability and extensibility will start to decrease fast, even if it has tests. Until now, only IDEs contained functionality to perform automated refactorings. And then even only PHPStorm contains the most important refactorings such as "extract method". .. note:: Refactoring is an important skill for your team to make software maintainable and keep it like that. Base these capabilities on the sound basis of an `individual Qafoo training`__ for your team. __ /services/training.html Today we release the `PHP Refactoring Browser `_, a refactoring tool written completely in PHP. It is based on several outstanding open-source libraries: - `PHP Parser `_ by Nikic - `PHP Token Reflection `_ by Ondřej Nešpor - `PHP Analyzer `_ by Johannes Schmitt The Browser currently supports the following refactorings: - Extract Method - Rename Local Variable - Convert Local to Instance Variable The result of each refactoring is a patch, which is printed to the screen. You can review the patch and then apply it to your source code using Unixs ``patch`` command. Let's discuss a sample code and apply some refactorings to it:: getMock('DependencyService'); $service = new FooService($dependency); $dependency->expects($this->once())->method('doSomething'); $value = $service->perform(); $this->assertEquals(42, $value); } } For our next test, we need the same test setup, so we want to refactor the first two lines into the ``setUp()`` method and convert the local variable into an instance variable:: $ php refactor.phar convert-local-to-instance-variable tests/FooServiceTest.php 6 dependency Prints:: --- a/tests/FooService.php +++ b/tests/FooService.php @@ -2,11 +2,13 @@ // tests/FooServiceTest.php class FooServiceTest extends PHPUnit_Framework_TestCase { + private $dependency; + public function testFoo() { - $dependency = $this->getMock('DependencyService'); + $this->dependency = $this->getMock('DependencyService'); - $service = new FooService($dependency); + $service = new FooService($this->dependency); - $dependency->expects($this->once())->method('doSomething'); + $this->dependency->expects($this->once())->method('doSomething'); $value = $service->perform(); We can apply the patch by calling the command again and pipe to ``|patch -p1``. Now we want to do the same to the ``$service`` variable:: $ php refactor.phar convert-local-to-instance-variable tests/FooServiceTest.php 10 service We get the patch:: --- a/tests/FooService.php +++ b/tests/FooService.php @@ -3,5 +3,7 @@ class FooServiceTest extends PHPUnit_Framework_TestCase { private $dependency; + private $service; + public function testFoo() @@ -8,5 +8,5 @@ { $this->dependency = $this->getMock('DependencyService'); - $service = new FooService($this->dependency); + $this->service = new FooService($this->dependency); $this->dependency->expects($this->once())->method('doSomething'); @@ -12,5 +12,5 @@ $this->dependency->expects($this->once())->method('doSomething'); - $value = $service->perform(); + $value = $this->service->perform(); $this->assertEquals(42, $value); Now we extract the first two lines into the ``setUp()`` method:: $ php refactor.phar extract-method tests/FooServiceTest.php 11-12 setUp We get the patch:: --- a/test.php +++ b/test.php @@ -9,6 +9,5 @@ public function testFoo() { - $this->dependency = $this->getMock('DependencyService'); - $this->service = new FooService($this->dependency); + $this->setUp(); $this->dependency->expects($this->once())->method('doSomething'); @@ -17,5 +17,11 @@ $this->assertEquals(42, $value); } + + private function setUp() + { + $this->dependency = $this->getMock('DependencyService'); + $this->service = new FooService($this->dependency); + } } And we can see the ``setUp()`` method is created in the class and called in ``testFoo()``. When we apply the patch we know that PHPUnit calls ``setUp()`` itself and requires it to be public, so we change this code manually to end up with:: dependency->expects($this->once())->method('doSomething'); $value = $this->service->perform(); $this->assertEquals(42, $value); } public function setUp() { $this->dependency = $this->getMock('DependencyService'); $this->service = new FooService($this->dependency); } } This project already has been a valuable tool for us in a customer project and we intent to make it much more useful over time: - Integration into Vim, using hot-keys to perform refactorings - Introducing more refactorings and improving the existing ones Currently you can easily break the refactorings when coming up with weird code-scenarios. We will try to handle as much edge-cases as PHP Parser, PHP Token Reflection and PHP Analyzer allow us to. To install the Refactoring Browser, head over to `it's website on Github `_ and download the PHAR file from there. Of course, `contributions are highly welcome`__ via pull requests on Github. __ https://github.com/QafooLabs/php-refactoring-browser Trackbacks ========== Comments ======== - Alan Francis at Thu, 02 Feb 2017 10:15:48 +0100 Can we use this tool to extract php functions which are beyond the scope of class than php methods?