🌙
Phan in Browser
PHP Version:
8.1
8.2
8.3
8.4
8.5 RC2
Phan Version:
5.5.1
5.5.2
v6 dev
php-ast Version:
1.1.2
1.1.3
Configure Plugins
📋 Share
🔑 GitHub
×
Loading...
Loading...
Loading...
Loading...
file1.php
+
×
use Phan\Config; use Phan\Issue; use Phan\IssueInstance; use Phan\Output\HTML; use Phan\Output\IssuePrinterInterface; use Symfony\Component\Console\Output\OutputInterface; use Phan\CLI; use Phan\Phan; error_reporting(E_ALL); ini_set('display_errors', 'stderr'); putenv('NO_COLOR=1'); try { $phar_path = '$PHAN_PHAR_PATH'; if (!file_exists($phar_path)) { fwrite(STDERR, "Could not load '$phar_path' - this may not have been included when generating this site with emscripten\n"); exit(1); } $phar = "phar://$phar_path"; gc_disable(); $data = require($phar . '/src/Phan/Language/Internal/ClassDocumentationMap.php'); require_once($phar . '/src/requirements.php'); $code_base = require_once($phar . '/src/codebase.php'); require_once($phar . '/src/Phan/Bootstrap.php'); // Create a stub .phan/config.php to suppress warning // Note: .phan directory is created by JavaScript stub loader // Don't create it again here to avoid "File exists" error // Just create the config file directly - file_put_contents will fail if dir doesn't exist if (!file_exists('.phan/config.php')) { try { file_put_contents('.phan/config.php', ' PHP_VERSION_ID >= 80400 ? '/phan/internal/stubs/spl.phan_php' // PHP 8.4+: typed constants + seek() : '/phan/internal/stubs/spl_php81.phan_php', // PHP 8.1-8.3: no typed constants, no seek() 'standard' => '/phan/internal/stubs/standard_templates.phan_php', // template annotations for array functions ]); // Mark SPL as needing template class replacement Config::setValue('autoload_internal_extension_signatures_template_classes', ['spl']); // Mark standard as needing template function signatures Config::setValue('autoload_internal_extension_signatures_template_functions', ['standard']); // Plugins will be set dynamically from JavaScript $ACTIVE_PLUGINS_PLACEHOLDER // This is stricter, though. Config::setValue('plugin_config', [ 'infer_pure_methods' => true, ]); $cli = CLI::fromRawValues([ 'output-mode' => 'html', 'allow-polyfill-parser' => false, 'redundant-condition-detection' => false, 'dead-code-detection' => true, 'no-progress-bar' => false, ], []); // Analyze the file list provided via the CLI $is_issue_found = Phan::analyzeFileList( $code_base, function (bool $recompute_file_list = false) use ($cli) : array { return $cli->getFileList(); } ); } catch (\Throwable $e) { echo "Caught $e\n"; }
function demo_error_handler(int $errno, string $errstr, string $errfile, int $errline) : bool { fwrite(STDERR, "$errfile:$errline [$errno] $errstr\n"); ob_start(); debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); fwrite(STDERR, ob_get_clean()); return false; } try { error_reporting(E_ALL); ini_set("display_errors", "stderr"); set_error_handler('demo_error_handler'); eval($CONTENTS_TO_ANALYZE); } catch (Throwable $e) { fwrite(STDERR, "Caught " . $e); }
use ast\flags; function get_flag_info(): array { static $info; if ($info !== null) { return $info; } foreach (ast\get_metadata() as $data) { if (empty($data->flags)) continue; $flagMap = []; foreach ($data->flags as $fullName) { $shortName = substr($fullName, strrpos($fullName, '\\') + 1); $flagMap[constant($fullName)] = $shortName; } $info[(int) $data->flagsCombinable][$data->kind] = $flagMap; } return $info; } function format_flags(int $kind, int $flags): string { list($exclusive, $combinable) = get_flag_info(); if (isset($exclusive[$kind])) { $flagInfo = $exclusive[$kind]; if (isset($flagInfo[$flags])) { return "{$flagInfo[$flags]} ($flags)"; } } else if (isset($combinable[$kind])) { $flagInfo = $combinable[$kind]; $names = []; foreach ($flagInfo as $flag => $name) { if ($flags & $flag) { $names[] = $name; } } if (!empty($names)) { return implode(" | ", $names) . " ($flags)"; } } return (string) $flags; } function ast_to_array($ast, bool $include_linenos = true): mixed { if ($ast instanceof ast\Node) { $result = [ 'kind' => ast\get_kind_name($ast->kind), ]; if ($include_linenos) { $result['lineno'] = $ast->lineno; if (isset($ast->endLineno)) { $result['endLineno'] = $ast->endLineno; } } if (ast\kind_uses_flags($ast->kind) || $ast->flags != 0) { $result['flags'] = $ast->flags; $result['flags_formatted'] = format_flags($ast->kind, $ast->flags); } $children = []; foreach ($ast->children as $key => $child) { $children[$key] = ast_to_array($child, $include_linenos); } if (!empty($children)) { $result['children'] = $children; } return $result; } else if ($ast === null) { return null; } else if (is_string($ast)) { return $ast; } else { return $ast; } } try { error_reporting(E_ALL); ini_set('display_errors', 'stderr'); $code = $CONTENTS_TO_ANALYZE; $ast_version = 120; // Latest AST version $ast = ast\parse_code($code, $ast_version); $output = [ 'ast_version' => $ast_version, 'ast' => ast_to_array($ast, true), ]; echo json_encode($output, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); } catch (ParseError $e) { fwrite(STDERR, "Parse Error: " . $e->getMessage() . "\n"); } catch (Throwable $e) { fwrite(STDERR, "Error: " . $e->getMessage() . "\n"); }
include '/tmp/vld_user_code.php';
function demo($param, $arg) : ?int { // Phan can infer types, detect missing elements, // and detect incorrect calls. global $argc; var_export(new my_class()); $cond = $param > 5; if (!($arg instanceof SplObjectStorage)) { return $argc; } $arg->attach($cond); $arg->atach(new stdClass()); $arg->attach( new MyClass($argc), [], 'extra' ); // Phan can detect redundant/impossible conditions // and unused variables. $always_true = is_bool($cond); echo "Missing variable is $argv\n"; return $arg; } class MyClass { public function __construct(string $x = null) { // and detect undeclared properties, etc. $this->x = $x; } } demo(2, new SplObjectStorage());
Initializing...
Configure Phan Plugins
×
Level 1
Level 2
Level 3
Level 4
Level 5