Analyze the given set of files and emit any issues
found to STDOUT.
public static analyzeFileList ( |
||
$code_base | A code base needs to be passed in because we require it to be initialized before any classes or files are loaded. | |
$file_path_list | array | A list of files to scan |
return | boolean | We emit messages to the configured printer and return true if issues were found. |
/** * This reads all files in `tests/files/src`, runs * the analyzer on each and compares the output * to the files's counterpart in * `tests/files/expected` * * @param string[] $test_file_list * @param string $expected_file_path * @dataProvider getTestFiles */ public function testFiles($test_file_list, $expected_file_path) { $expected_output = ''; if (is_file($expected_file_path)) { // Read the expected output $expected_output = trim(file_get_contents($expected_file_path)); } $stream = new BufferedOutput(); $printer = new PlainTextPrinter(); $printer->configureOutput($stream); Phan::setPrinter($printer); Phan::setIssueCollector(new BufferingCollector()); Phan::analyzeFileList($this->code_base, $test_file_list); $output = $stream->fetch(); // Uncomment to save the output back to the expected // output. This should be done for error message // text changes and only if you promise to be careful. /* $saved_output = $output; $test_file_elements= explode('/', $test_file_list[0]); $test_file_name = array_pop($test_file_elements); $saved_output = preg_replace('/[^ :\n]*\/' . $test_file_name . '/', '%s', $saved_output); $saved_output = preg_replace('/closure_[^\(]*\(/', 'closure_%s(', $saved_output); if (!empty($saved_output) && strlen($saved_output) > 0) { $saved_output .= "\n"; } file_put_contents($expected_file_path, $saved_output); $expected_output = trim(file_get_contents($expected_file_path)); */ $wanted_re = preg_replace('/\\r\\n/', "\n", $expected_output); // do preg_quote, but miss out any %r delimited sections $temp = ""; $r = "%r"; $startOffset = 0; $length = strlen($wanted_re); while ($startOffset < $length) { $start = strpos($wanted_re, $r, $startOffset); if ($start !== false) { // we have found a start tag $end = strpos($wanted_re, $r, $start + 2); if ($end === false) { // unbalanced tag, ignore it. $end = $start = $length; } } else { // no more %r sections $start = $end = $length; } // quote a non re portion of the string $temp = $temp . preg_quote(substr($wanted_re, $startOffset, $start - $startOffset), '/'); // add the re unquoted. if ($end > $start) { $temp = $temp . '(' . substr($wanted_re, $start + 2, $end - $start - 2) . ')'; } $startOffset = $end + 2; } $wanted_re = $temp; $wanted_re = str_replace(['%binary_string_optional%'], 'string', $wanted_re); $wanted_re = str_replace(['%unicode_string_optional%'], 'string', $wanted_re); $wanted_re = str_replace(['%unicode\\|string%', '%string\\|unicode%'], 'string', $wanted_re); $wanted_re = str_replace(['%u\\|b%', '%b\\|u%'], '', $wanted_re); // Stick to basics $wanted_re = str_replace('%e', '\\' . DIRECTORY_SEPARATOR, $wanted_re); $wanted_re = str_replace('%s', '[^\\r\\n]+', $wanted_re); $wanted_re = str_replace('%S', '[^\\r\\n]*', $wanted_re); $wanted_re = str_replace('%a', '.+', $wanted_re); $wanted_re = str_replace('%A', '.*', $wanted_re); $wanted_re = str_replace('%w', '\\s*', $wanted_re); $wanted_re = str_replace('%i', '[+-]?\\d+', $wanted_re); $wanted_re = str_replace('%d', '\\d+', $wanted_re); $wanted_re = str_replace('%x', '[0-9a-fA-F]+', $wanted_re); $wanted_re = str_replace('%f', '[+-]?\\.?\\d+\\.?\\d*(?:[Ee][+-]?\\d+)?', $wanted_re); $wanted_re = str_replace('%c', '.', $wanted_re); // %f allows two points "-.0.0" but that is the best *simple* expression $this->assertRegExp("/^{$wanted_re}\$/", $output, "Unexpected output in {$test_file_list[0]}"); }
/** * This reads all files in `tests/files/src`, runs * the analyzer on each and compares the output * to the files's counterpart in * `tests/files/expected` * * @param string $test_file_path * @param string $expected_file_path * @dataProvider getTestFiles */ public function testFiles($test_file_path, $expected_file_path) { $expected_output = ''; if (is_file($expected_file_path)) { // Read the expected output $expected_output = trim(file_get_contents($expected_file_path)); } // Start reading everything sent to STDOUT // and compare it to the expected value once // the analzyer finishes running ob_start(); try { // Run the analyzer Phan::analyzeFileList($this->codeBase, [$test_file_path]); } catch (\Exception $exception) { // TODO: inexplicably bad things happen here // print "\n" . $exception->getMessage() . "\n"; } $output = trim(ob_get_clean()); // Uncomment to save the output back to the expected // output. This should be done for error message // text changes and only if you promise to be careful. /* $saved_output = $output; $saved_output = preg_replace('/[^ :\n]*\/'.$test_file_name.'/', '%s', $saved_output); $saved_output = preg_replace('/closure_[^\(]*\(/', 'closure_%s(', $saved_output); if (!empty($saved_output) && strlen($saved_output) > 0) { $saved_output .= "\n"; } file_put_contents($expected_file_path, $saved_output); $expected_output = trim(file_get_contents($expected_file_path)); */ $wanted_re = preg_replace('/\\r\\n/', "\n", $expected_output); // do preg_quote, but miss out any %r delimited sections $temp = ""; $r = "%r"; $startOffset = 0; $length = strlen($wanted_re); while ($startOffset < $length) { $start = strpos($wanted_re, $r, $startOffset); if ($start !== false) { // we have found a start tag $end = strpos($wanted_re, $r, $start + 2); if ($end === false) { // unbalanced tag, ignore it. $end = $start = $length; } } else { // no more %r sections $start = $end = $length; } // quote a non re portion of the string $temp = $temp . preg_quote(substr($wanted_re, $startOffset, $start - $startOffset), '/'); // add the re unquoted. if ($end > $start) { $temp = $temp . '(' . substr($wanted_re, $start + 2, $end - $start - 2) . ')'; } $startOffset = $end + 2; } $wanted_re = $temp; $wanted_re = str_replace(['%binary_string_optional%'], 'string', $wanted_re); $wanted_re = str_replace(['%unicode_string_optional%'], 'string', $wanted_re); $wanted_re = str_replace(['%unicode\\|string%', '%string\\|unicode%'], 'string', $wanted_re); $wanted_re = str_replace(['%u\\|b%', '%b\\|u%'], '', $wanted_re); // Stick to basics $wanted_re = str_replace('%e', '\\' . DIRECTORY_SEPARATOR, $wanted_re); $wanted_re = str_replace('%s', '[^\\r\\n]+', $wanted_re); $wanted_re = str_replace('%S', '[^\\r\\n]*', $wanted_re); $wanted_re = str_replace('%a', '.+', $wanted_re); $wanted_re = str_replace('%A', '.*', $wanted_re); $wanted_re = str_replace('%w', '\\s*', $wanted_re); $wanted_re = str_replace('%i', '[+-]?\\d+', $wanted_re); $wanted_re = str_replace('%d', '\\d+', $wanted_re); $wanted_re = str_replace('%x', '[0-9a-fA-F]+', $wanted_re); $wanted_re = str_replace('%f', '[+-]?\\.?\\d+\\.?\\d*(?:[Ee][+-]?\\d+)?', $wanted_re); $wanted_re = str_replace('%c', '.', $wanted_re); // %f allows two points "-.0.0" but that is the best *simple* expression $this->assertRegExp("/^{$wanted_re}\$/", $output, "Unexpected output in {$test_file_path}"); }
<?php declare (strict_types=1); // Check the environment to make sure Phan can run successfully require_once __DIR__ . '/requirements.php'; // Build a code base based on PHP internally defined // functions, methods and classes before loading our // own $code_base = (require_once __DIR__ . '/codebase.php'); require_once __DIR__ . '/Phan/Bootstrap.php'; use Phan\CLI; use Phan\CodeBase; use Phan\Config; use Phan\Phan; // Create our CLI interface and load arguments $cli = new CLI(); $file_list = $cli->getFileList(); // If requested, expand the file list to a set of // all files that should be re-analyzed if (Config::get()->expand_file_list) { assert((bool) Config::get()->stored_state_file_path, 'Requesting an expanded dependency list can only ' . ' be done if a state-file is defined'); // Analyze the file list provided via the CLI $file_list = Phan::expandedFileList($code_base, $file_list); } // Analyze the file list provided via the CLI Phan::analyzeFileList($code_base, $file_list);
declare (strict_types=1); // Phan does a ton of GC and this offers a major speed // improvment if your system can handle it (which it // should be able to) gc_disable(); // Check the environment to make sure Phan can run successfully require_once __DIR__ . '/requirements.php'; // Build a code base based on PHP internally defined // functions, methods and classes before loading our // own $code_base = (require_once __DIR__ . '/codebase.php'); require_once __DIR__ . '/Phan/Bootstrap.php'; use Phan\CLI; use Phan\CodeBase; use Phan\Config; use Phan\Phan; // Create our CLI interface and load arguments $cli = new CLI(); $file_list = $cli->getFileList(); // If requested, expand the file list to a set of // all files that should be re-analyzed if (Config::get()->expand_file_list) { assert((bool) Config::get()->stored_state_file_path, 'Requesting an expanded dependency list can only ' . ' be done if a state-file is defined'); // Analyze the file list provided via the CLI $file_list = Phan::expandedFileList($code_base, $file_list); } // Analyze the file list provided via the CLI $is_issue_found = Phan::analyzeFileList($code_base, $file_list); // Provide an exit status code based on if // issues were found exit($is_issue_found ? EXIT_ISSUES_FOUND : EXIT_SUCCESS);
<?php declare (strict_types=1); assert(extension_loaded('ast'), "The php-ast extension must be loaded in order for Phan to work. See https://github.com/etsy/phan#getting-it-running for more details."); assert((int) phpversion()[0] >= 7, "Phan requires PHP version 7 or greater. See https://github.com/etsy/phan#getting-it-running for more details."); // Grab these before we define our own classes $internal_class_name_list = get_declared_classes(); $internal_interface_name_list = get_declared_interfaces(); $internal_trait_name_list = get_declared_traits(); $internal_function_name_list = get_defined_functions()['internal']; require_once __DIR__ . '/Phan/Bootstrap.php'; use Phan\CLI; use Phan\CodeBase; use Phan\Config; use Phan\Phan; // Create our CLI interface and load arguments $cli = new CLI(); $code_base = new CodeBase($internal_class_name_list, $internal_interface_name_list, $internal_trait_name_list, $internal_function_name_list); // If requested, expand the file list to a set of // all files that should be re-analyzed if (Config::get()->expanded_dependency_list) { assert((bool) Config::get()->stored_state_file_path, 'Requesting an expanded dependency list can only ' . ' be done if a state-file is defined'); // Analyze the file list provided via the CLI $dependency_file_list = Phan::dependencyFileList($code_base, $cli->getFileList()); // Emit the expanded file list print implode("\n", $dependency_file_list) . "\n"; exit(1); } // Analyze the file list provided via the CLI Phan::analyzeFileList($code_base, $cli->getFileList());