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?