diff --git a/blog-data/2013-03-07-comparing-php-application-definitions/console-diff.png b/blog-data/2013-03-07-comparing-php-application-definitions/console-diff.png new file mode 100644 index 0000000..e65e52d Binary files /dev/null and b/blog-data/2013-03-07-comparing-php-application-definitions/console-diff.png differ diff --git a/blog/_posts/2013-03-07-comparing-php-application-definitions.md b/blog/_posts/2013-03-07-comparing-php-application-definitions.md new file mode 100644 index 0000000..3e8394f --- /dev/null +++ b/blog/_posts/2013-03-07-comparing-php-application-definitions.md @@ -0,0 +1,181 @@ +--- +title: Comparing PHP Application Definitions +layout: post +tags: code diff language php xslt +description: Identifying how classes/interfaces changed between versions. +code: https://github.com/dpb587/diff-defn.php +--- + +While working to update a PHP project, I thought it'd be helpful if I could systematically qualify significant code +changes between versions. I could weed through a massive line diff, but that's costly if many changes aren't ultimately +affecting my API dependencies. Typically I only care about how interfaces and classes change in their usage of methods, +method arguments, variables, and scope. + +I did a bit of research on the idea and found [several][7] [different][8] [questions][9], a few [referenced][10] +[products][11], and a short [article][12] on the idea. However I wasn't able to find a good PHP (or even generic) option +which was open-source and something I could easily try out. + +To that end, I made a prototype for a language-intelligent/OOP-diff/structured diff engine that can summarize many of +the programmatic changes in an easily readable report which links definitions back to their file and line number for +more detailed review... + + + + +### Usage + +If I were upgrading my application with a [`symfony/Console`][1] dependency from `v2.0.22` to `v2.2.0`, I could generate +the diff of definitions with: + +{% highlight console %} +$ git clone git://github.com/dpb587/diff-defn.php.git diff-defn.php && cd !$ +$ php composer.phar install +$ ./bin/diff-defn.php diff:show --exclude='/Tests/' git://github.com/symfony/Console.git v2.0.22 v2.2.0 > output.html +$ open output.html +{% endhighlight %} + +Take a look at several other reports using the default stylesheet: + + * [`doctrine/dbal`][2] (`2.1.7` → `2.3.2`) + * [`fabpot/Twig`][3] (`v1.10.0` → `v1.12.2`) + * [`symfony/symfony`][4] (`v2.0.22` → `v2.2.0`) + * [`zendframework/zf2`][5] (`release-2.0.0` → `release-2.1.3`) + + +### Behind the Scenes + +The logic behind the command looks like: + + 1. Use version control to diff the two versions and see what files were changed. + 2. Use [nikic/php-parser][6] to parse the PHP files in both their initial and final commit... + * Build separate structures for both the initial and final code states. + * Use visitors to analyze definitions, language or application-specific definitions. + 3. Use some logic to compare the initial and final structures and create a new structured diff with only the relevant + definitions that changed (including both old and new). + 4. Apply a stylesheet to the diff structure to generate human-readable output. + +The structures are simple classes which can be dumped to XML. And technically, aside from the step of parsing of PHP +files, this is very language-agnostic. For example, the XML representation of the initial or final commit looks like: + +{% highlight xml %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{% endhighlight %} + +And after the initial and final commit are compared, the resulting structured diff looks like: + +{% highlight xml %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{% endhighlight %} + + +### Going Further + +Being able to parse files and have their differences stored in static, semi-agnostic format allows for some interesting +usages: + + * search for specific changes, like which class methods have had their typehint changed (e.g. xpath + `//class/function/function-param/defn-attr[@id="typehint" and @diff="changed" and @value="Psr\Log\LoggerInterface"]`) + * combine search results with other automated tools for updating impacted application code or explicitly requiring + reviews for changes breaking compatibility standards + * generating lists about new interfaces/classes, dropped definitions, newly limited scopes + * when using test naming conventions, specifically test and verify the code's tests are run + * instead of simple "lines of code" stats, also track classes/methods/functions + * writing post-commit rules based on definition searches (e.g. email a maintainer whenever a critical class is touched) + +Since the analysis and the serialized, static representation are distinct steps, this also allows for custom, +application-specific analysis information like: + + * in aspect-oriented code, analyzing `@Aspects(...)` and including them in reports + * tying code-linting tool results to flag specific methods/properties that have issues + * additional flags to monitor if function logic changed vs formatting/comments (even if the API is unchanged) + +And unlike some of the other tools I ran into, the static representation is not itself inherently readable; it needs a +stylesheet to make it human-friendly. This makes the results potentially reusable for multiple different reports. + + +### Summary + +I've published this work-in-progress code to [dpb587/diff-defn.php][13] in case you want to try it out with your own PHP +repositories. It's certainly not a replacement of reading changelogs and understanding what upstream changes are being +made, but I have found it interesting and helpful to identifying breaking changes. + + + [1]: https://github.com/symfony/Console + [2]: http://static.dpb587.me/2013-03-07-comparing-php-application-definitions/doctrine-dbal-2.1.7..2.3.2.html + [3]: http://static.dpb587.me/2013-03-07-comparing-php-application-definitions/fabpot-Twig-v1.10.0..v1.12.2.html + [4]: http://static.dpb587.me/2013-03-07-comparing-php-application-definitions/symfony-symfony-v2.0.22..v2.2.0.html + [5]: http://static.dpb587.me/2013-03-07-comparing-php-application-definitions/zendframework-zf2-release-2.0.0..release-2.1.3.html + [6]: https://github.com/nikic/php-parser + [7]: http://stackoverflow.com/questions/77931/do-you-know-of-any-language-aware-diffing-tools + [8]: http://stackoverflow.com/questions/2828795/is-there-a-language-aware-diff + [9]: http://discuss.fogcreek.com/joelonsoftware5/default.asp?cmd=show&ixPost=155585&ixReplies=18 + [10]: http://www.semdesigns.com/Products/SmartDifferencer/index.html + [11]: http://www.schneidersoft.com/Products/OOP-DIFF/OOP-DIFF.aspx + [12]: http://www.itworld.com/software/231515/usenix-dartmouth-expanding-diff-grep-unix-tools + [13]: https://github.com/dpb587/diff-defn.php diff --git a/include/site/screen.css b/include/site/screen.css index 0b7991a..a9ba6d1 100644 --- a/include/site/screen.css +++ b/include/site/screen.css @@ -237,3 +237,10 @@ dl dd { section.layout-post .meta.meta-social { display: none; } + +section.layout-post section img { + background-color: #F3F3F3; + border: #D8D8D8 solid 1px; + border-radius: 1px; + padding: 4px; +} diff --git a/projects.html b/projects.html index 2d76b4c..a4aab87 100755 --- a/projects.html +++ b/projects.html @@ -8,7 +8,7 @@ layout: default

I like tinkering with ideas and seeing where they end up. Some of my work ends up on - GitHub, but here are some of my noteworthy projects… + GitHub and these are a few of my personal favorites…

Personal

@@ -17,6 +17,20 @@ layout: default A few personal projects I've invested in…

+

PHP Diff Engine

+ +

+ A language-aware diff engine for comparing PHP classes/interfaces/functions. +

+ +
+
github
+
dpb587/diff-defn.php
+ +
blog
+
Comparing PHP Application Definitions (2013-03-07)
+
+

CLI for OpenGrok

@@ -26,6 +40,9 @@ layout: default

github
dpb587/opengrok-cli
+ +
blog
+
OpenGrok Cli (2013-01-21)
@@ -33,7 +50,7 @@ layout: default

I would not and could not be the developer I am today without the time others have invested in producing - quality, open source software. For my modest part, I've been able to contribute to the following: + quality, open source software. For my modest part, I've been able to contribute to the following…