1

Does PHP_CodeSniffer have an API I can use, rather than run the command line?

So given a string of PHP code, $code, and Composer ensuring loading of the PHP_CodeSniffer code, is there something I can do such as:

// Pseudocode!
$code_sniffer = new PHPCodeSniffer;
$result = $code_sniffer->sniff($code);

rather than go via the command line with something like:

$result = exec(sprintf('echo %s | vendor/bin/phpcs', escapeshellarg($code)));
1stthomas
  • 731
  • 2
  • 15
  • 22
joachim
  • 28,554
  • 13
  • 41
  • 44

2 Answers2

2

There is, but you need to write more code than that.

Take a look at the example here: https://gist.github.com/gsherwood/aafd2c16631a8a872f0c4a23916962ac

That example allows you to sniff a piece of code that isn't written to a file yet, and set up things like the standard to use (could also be a ruleset.xml file).

Another example, that uses the JS tokenizer instead of PHP + pulls content from an existing file, is available here: https://gist.github.com/gsherwood/f17cfc90f14a9b29eeb6b2e99e6e7f66

It is shorter because it doesn't use as many options.

Greg Sherwood
  • 6,992
  • 2
  • 29
  • 24
  • Thanks! That looks like it's for PHPCS 3. Unfortunately, the standard I am using is still on 2, so I had to figure it out for that. I'll post what I've got working as a new answer. – joachim Nov 14 '17 at 23:06
1

Here's what I got working for PHPCS 2:

PHP_CodeSniffer::setConfigData(
  'installed_paths',
  // The path to the standard I am using.
  __DIR__ . '/../../vendor/drupal/coder/coder_sniffer',
  TRUE
);


$phpcs = new PHP_CodeSniffer(
  // Verbosity.
  0,
  // Tab width
  0,
  // Encoding.
  'iso-8859-1',
  // Interactive.
  FALSE
);

$phpcs->initStandard('Drupal');

// Mock a PHP_CodeSniffer_CLI object, as the PHP_CodeSniffer object expects
// to have this and be able to retrieve settings from it.
// (I am using PHPCS within tests, so I have Prophecy available to do this. In another context, just creating a subclass of PHP_CodeSniffer_CLI set to return the right things would work too.) 
$prophet = new \Prophecy\Prophet;
$prophecy = $prophet->prophesize();
$prophecy->willExtend(\PHP_CodeSniffer_CLI::class);
// No way to set these on the phpcs object.
$prophecy->getCommandLineValues()->willReturn([
  'reports' => [
    "full" => NULL,
  ],
  "showSources" => false,
  "reportWidth" => null,
  "reportFile" => null
]);
$phpcs_cli = $prophecy->reveal();
// Have to set these properties, as they are read directly, e.g. by
// PHP_CodeSniffer_File::_addError()
$phpcs_cli->errorSeverity = 5;
$phpcs_cli->warningSeverity = 5;

// Set the CLI object on the PHP_CodeSniffer object.
$phpcs->setCli($phpcs_cli);

// Process the file with PHPCS.
$phpcsFile = $phpcs->processFile(NULL, $code);

$errors   = $phpcsFile->getErrorCount();
$warnings = $phpcsFile->getWarningCount();

$total_error_count = ($phpcsFile->getErrorCount() + $phpcsFile->getWarningCount());

// Get the reporting to process the errors.
$this->reporting = new \PHP_CodeSniffer_Reporting();
$reportClass = $this->reporting->factory('full');

// This gets you an array of all the messages which you can easily work over.
$reportData  = $this->reporting->prepareFileReport($phpcsFile);

// This formats the report, but prints it directly.
$reportClass->generateFileReport($reportData, $phpcsFile);
joachim
  • 28,554
  • 13
  • 41
  • 44