Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/sebastianbergmann/de-legacy-fy

Tool for dealing with legacy PHP code
https://github.com/sebastianbergmann/de-legacy-fy

Last synced: about 2 months ago
JSON representation

Tool for dealing with legacy PHP code

Awesome Lists containing this project

README

        

# de-legacy-fy

[Legacy code is code without tests.](http://c2.com/cgi/wiki?WorkingEffectivelyWithLegacyCode)
Over the years I have helped many a team introduce (unit) testing into a legacy
code base, making it "less legacy" step by step.

The `de-legacy-fy` command-line tool is an attempt to put concepts and ideas
that proved to be effective at dealing with legacy PHP applications into code
and make them as reusable as possible.

## Installation

### PHP Archive (PHAR)

The easiest way to obtain de-legacy-fy is to download a [PHP Archive (PHAR)](https://secure.php.net/phar) that has all required dependencies of de-legacy-fy bundled in a single file:

```
$ wget https://phar.phpunit.de/de-legacy-fy.phar
$ chmod +x de-legacy-fy.phar
$ mv de-legacy-fy.phar /usr/local/bin/de-legacy-fy
```

You can also immediately use the PHAR after you have downloaded it, of course:

```
$ wget https://phar.phpunit.de/de-legacy-fy.phar
$ php de-legacy-fy.phar
```

### Composer

You can add this tool as a local, per-project, development-time dependency to your project using [Composer](https://getcomposer.org/):

```
$ composer require --dev sebastian/de-legacy-fy
```

You can then invoke it using the `vendor/bin/de-legacy-fy` executable.

## Usage Examples

### Generating characterization tests using execution trace data

[Characterization Tests are an attempt to lock existing behavior into an untested or undocumented system.](http://c2.com/cgi/wiki?CharacterizationTest) They are described briefly in Michael Feathers' book ["Working Effectively With Legacy Code"](http://c2.com/cgi/wiki?WorkingEffectivelyWithLegacyCode), among other places.

We can automatically generate a [data provider](http://phpunit.de/manual/current/en/writing-tests-for-phpunit.html#writing-tests-for-phpunit.data-providers) for a PHPUnit-based characterization test using [execution trace](http://xdebug.org/docs/execution_trace) data that we can collect with [Xdebug](http://xdebug.org/).

Consider the following rather contrived and simple example:

```php
decode('aTozOw=='), $this->decode('aToxOw=='), $this->decode('aToyOw==')]
];
}

/**
* @param string $serializedValue
*
* @return mixed
*/
private function decode($serializedValue)
{
return unserialize(base64_decode($serializedValue));
}
}
```

All that is left for us to do in order to implement the characterization test can be seen below:

```php
assertEquals($expected, add($a, $b));
}

/**
* @return array
*/
public function provider()
{
return [
[$this->decode('aTozOw=='), $this->decode('aToxOw=='), $this->decode('aToyOw==')]
];
}

/**
* @param string $serializedValue
*
* @return mixed
*/
private function decode($serializedValue)
{
return unserialize(base64_decode($serializedValue));
}
}
```

### Wrapping a static API class

[Static methods are death to testability.](http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/)
It is characteristic for a legacy code base to use global state and static
methods. Sometimes there are "library classes" that only contain static
methods:

```php
library = $library;
}

public function process()
{
// ...

$this->library->doSomething('...', '...');

// ...
}
}
```

The `Processor` class does not use the legacy `Library` class directly anymore
and can be tested in isolation from it (as we can now stub or mock the
`LibraryWrapper` class).

Using the concept of [branch-by-abstraction](http://martinfowler.com/bliki/BranchByAbstraction.html)
we can now write new code that uses the `LibraryWrapper` class and migrate old
code from `Library` to `LibraryWrapper`. Eventually we can reimplement the
functionality of `Library` inside the `LibraryWrapper` class. Once no code
relies on `Library` anymore we can delete `Library` and rename `LibraryWrapper`
to `Library`.