Интеграция PHPMD (PHP Mess Detector) в Eclipse Mars

Перед выпуском Mars было возможно установить поддержку PHPMD в Eclipse, хотя и с некоторые предостережения и трудности.

Теперь поддержка со стороны PTI, похоже, полностью удалена, даже если разработка PHPMD не остановилась и PHPMD предлагает некоторые функции, которых нет у других инструментов: например, обнаружить неиспользуемые переменные.

Для этой последней функции я нашел не слишком свежий плагин CodeSniffer это делает трюк. Это также некоторые нюхают это должно сработать, но они, похоже, не работают для меня, или, по крайней мере, не во всех случаях: у меня есть проект, требующий рефакторинга, для которого у меня есть 11 предупреждений из CodeSniffer и 2524 из PHPMD.

Я думаю, что у меня есть простой и не элегантный способ вставить PHPMD обратно, но прежде чем делать тот, Я задавался вопросом, есть ли у кого-то эта та же самая проблема / потребность, и удалось ли ему как-то решить ее.

0

Решение

Хорошо, вот так.

У меня есть двоичный файл PHPMD, который работает из командной строки. Что я планировал сделать, так это вставить свой вывод в плагин CodeSniffer, «обогатить» последнее сообщениями PHPMD.

Для этого я покалечил phpcs.php который входит в мой plugins/org.ppsrc.eclipse.pti.tools.codesniffer_.../php/tools каталог.

(Поскольку у меня есть другая проблема с CodeSniffer, это то, что он часто повторно сканирует файлы должен Чтобы узнать о, я решил дать CodeSniffer память.

Прежде всего, я извлекаю последний аргумент для вызова, который является анализируемым файлом (строки, отмеченные +++, являются моими дополнениями / изменениями):

// Optionally use PHP_Timer to print time/memory stats for the run.
// Note that the reports are the ones who actually print the data
// as they decide if it is ok to print this data to screen.
@include_once 'PHP/Timer.php';
if (class_exists('PHP_Timer', false) === true) {
PHP_Timer::start();
}

if (is_file(dirname(__FILE__).'/../CodeSniffer/CLI.php') === true) {
include_once dirname(__FILE__).'/../CodeSniffer/CLI.php';
} else {
include_once 'PHP/CodeSniffer/CLI.php';
}

+++ $lastArgument   = array_pop($_SERVER['argv']);

Затем я добавляю некоторые флаги, которые CS, кажется, не проходит, и которые мне нужны, такие как игнорирование некоторых каталогов:

+++ $_SERVER['argv'][]  = '--ignore=tests,vendor,cache';
+++ $_SERVER['argv'][]  = $lastArgument;

Затем вызов CS продолжается, но теперь я сохраняю его результаты в буфере, а не отправляю их прямо в Eclipse.

$phpcs = new PHP_CodeSniffer_CLI();
$phpcs->checkRequirements();
+++ ob_start();
$numErrors = $phpcs->process();

+++ $dom    = new DOMDocument();
+++ $dom->loadXML(ob_get_clean());

+++ $cs     = $dom->getElementsByTagName('phpcs')->item(0);
+++ $xpath  = new DOMXPath($dom);

Теперь у меня есть готовый вывод PHPCS в виде XML.

Осталось только запустить PHPMD с использованием собственного синтаксиса.

// Add PHPMD.
$mdCmd  = "C:/PHP/composer/vendor/phpmd/phpmd/src/bin/phpmd \"{$lastArgument}\" xml \"C:/Program Files/eclipse/plugins/org.phpsrc.eclipse.pti.library.pear_1.2.2.R20120127000000/php/library/PEAR/data/PHP_PMD/resources/rulesets/codesize.xml,C:/Program Files/eclipse/plugins/org.phpsrc.eclipse.pti.library.pear_1.2.2.R20120127000000/php/library/PEAR/data/PHP_PMD/resources/rulesets/naming.xml,C:/Program Files/eclipse/plugins/org.phpsrc.eclipse.pti.library.pear_1.2.2.R20120127000000/php/library/PEAR/data/PHP_PMD/resources/rulesets/unusedcode.xml\"";

…и загрузите его в другой XML:

    fprintf(STDERR, $mdCmd . "\n");
$dompmd = new DOMDocument();
$dompmd->loadXML($mdxml = shell_exec($mdCmd));

Теперь я получаю все ошибки из объекта PMD и добавляю его в CS:

    $files  = $dompmd->getElementsByTagName('file');
foreach ($files as $file) {
$name   = $file->getAttribute('name');
$list   = $xpath->query("//file[@name=\"{$name}\"]");
if (null === $list) {
continue;
}
$csFile = $list->item(0);
if (null === $csFile) {
// No errors from CS.
$csFile = $dom->createElement('file');
$csFile->setAttribute('name', $name);
$csFile->setAttribute('errors', 0);
$csFile->setAttribute('warnings', 0);
$csFile->setAttribute('fixable', 0);
$cs->appendChild($csFile);
}
$errs   = 0;
foreach ($file->childNodes as $violation) {
if ($violation instanceof \DOMText) {
continue;
}
$error  = $dom->createElement('warning', trim($violation->nodeValue));$error->setAttribute('line', $violation->getAttribute('beginline'));
$error->setAttribute('column', 1);
$error->setAttribute('source', 'PHPMD.' . $violation->getAttribute('ruleset'));
$error->setAttribute('severity', $violation->getAttribute('priority'));
$error->setAttribute('fixable', 0);

$csFile->appendChild($error);

$errs++;
}
$csFile->getAttributeNode('errors')->value += $errs;
}

Наконец, отправьте данные обратно в Eclipse:

print $dom->saveXML();
exit($numErrors ? 1: 0);

Поскольку у меня есть еще одна проблема с CodeSniffer, это то, что он часто повторно сканирует файлы. должен Чтобы узнать о, я решил дать CodeSniffer память. Это довольно просто: я могу сохранить временный файл с сохраненным XML и именем, созданным из MD5 исходного имени файла а также его содержание:

/tmp/68ce1959ef67bcc94e05084e2e20462a.76e55e72f32156a20a183de82fe0b3b6.xml

Поэтому, когда PHPCS попросили проанализировать /path/to/file/so-and-so.php, будет:

  • создать MD5 имени файла.
  • создайте MD5 его содержимого.
  • если /tmp/md5file.md5content.xml не существует:
    • удалите все файлы /tmp/md5file.*.xml: они устарели.
    • запустить код, как указано выше.
    • сохранить результаты в /tmp/md5file.md5content.xml
  • выведите содержимое /tmp/md5file.md5content.xml.
1

Другие решения

Других решений пока нет …