PHPDoctor: type and PHPDoc quality profiling for PHP projects.
If you already use PHPStan for your type checks but sometimes someone in the team still commit non typed code, then PHPDoctor is for you.
PHPDoctor keeps its original PHPDoc doctor identity as the first diagnostic stage and grows from there. It checks missing native types, missing or wrong PHPDoc types, deprecated documentation gaps, parse errors, and other type-documentation regressions without trying to replace PHPStan, Psalm, or a generic architecture review.
curl -L https://github.com/voku/PHPDoctor/releases/latest/download/phpdoctor.phar -o phpdoctor.phar
chmod +x phpdoctor.pharAll releases: https://github.com/voku/PHPDoctor/releases
composer require-dev voku/phpdoctorUsage:
analyse [options] [--] <path...>
Arguments:
path The path to analyse
Options:
--autoload-file[=AUTOLOAD-FILE] The path to your autoloader. [default: ""]
--access[=ACCESS] Check for "public|protected|private" methods. [default: "public|protected|private"]
--skip-ambiguous-types-as-error[=SKIP-AMBIGUOUS-TYPES-AS-ERROR] Skip check for ambiguous types. (false or true) [default: "false"]
--skip-deprecated-functions[=SKIP-DEPRECATED-FUNCTIONS] Skip check for deprecated functions / methods. (false or true) [default: "false"]
--skip-functions-with-leading-underscore[=SKIP-FUNCTIONS-WITH-LEADING-UNDERSCORE] Skip check for functions / methods with leading underscore. (false or true) [default: "false"]
--skip-parse-errors[=SKIP-PARSE-ERRORS] Skip parse errors in the output. (false or true) [default: "true"]
--path-exclude-regex[=PATH-EXCLUDE-REGEX] Skip some paths via regex e.g. "#/vendor/|/other/.*/path/#i" [default: "#/vendor/|/tests/#i"]
--file-extensions[=FILE-EXTENSIONS] Check different file extensions e.g. ".php|.php4|.php5|.inc" [default: ".php"]
--profile[=PROFILE] Show a type and PHPDoc quality profile summary. (false or true) [default: "false"]
--output-format[=OUTPUT-FORMAT] Output format for the analysis result. (text, json or github) [default: "text"]
--baseline-file[=BASELINE-FILE] Compare against a PHPDoctor JSON baseline file so only new findings fail.
--generate-baseline[=GENERATE-BASELINE] Write the current type and PHPDoc profile to --baseline-file. (false or true) [default: "false"]
PHPDoctor is evolving in focused stages:
- keep the existing PHPDoc and native type diagnostics as the seed;
- add structured profiling around the current findings;
- support JSON baselines so CI can fail only on newly introduced findings;
- provide project-level summaries for actionable type documentation coverage;
- expose machine-readable JSON for CI dashboards.
This stays intentionally narrow: PHPDoctor profiles type documentation quality and controlled regressions, not generic code quality scores.
Show a profile summary:
php vendor/bin/phpdoctor analyse src --profile=trueGenerate a baseline:
php vendor/bin/phpdoctor analyse src --baseline-file=phpdoctor-baseline.json --generate-baseline=trueUse the baseline in CI so only new findings fail:
php vendor/bin/phpdoctor analyse src --baseline-file=phpdoctor-baseline.jsonEmit JSON for dashboards:
php vendor/bin/phpdoctor analyse src --output-format=jsonEmit GitHub Actions workflow annotations:
php vendor/bin/phpdoctor analyse src --output-format=githubUse GitHub Actions annotations with a minimal workflow step:
- name: Run PHPDoctor GitHub annotations
run: php vendor/bin/phpdoctor analyse src --output-format=githubUse baseline-aware GitHub Actions annotations so only new findings are annotated:
- name: Run PHPDoctor GitHub annotations with baseline
run: php vendor/bin/phpdoctor analyse src --baseline-file=phpdoctor-baseline.json --output-format=githubExit codes:
0: no findings, or no new findings when--baseline-fileis active1: findings found, or new findings found when--baseline-fileis active2: CLI, configuration, or baseline errors
Parse a string:
$code = '
<?php declare(strict_types = 1);
class HelloWorld
{
/**
* @param mixed $date
*/
public function sayHello($date): void
{
echo \'Hello, \' . $date->format(\'j. n. Y\');
}
}';
$phpdocErrors = PhpCodeChecker::checkFromString($code);
// [8]: missing parameter type for HelloWorld->sayHello() | parameter:date']You can use <phpdoctor-ignore-this-line/> in @param or @return phpdocs to ignore the errors directly in your code.
/**
* @param mixed $lall <p>this is mixed but it is ok, because ...</p> <phpdoctor-ignore-this-line/>
*
* @return array <phpdoctor-ignore-this-line/>
*/
function foo_ignore($lall) {
return $lall;
}The PHAR is built automatically via GitHub Actions whenever a new version tag (*.*.*) is pushed.
The resulting phpdoctor.phar is attached to the corresponding GitHub Release and can be downloaded directly:
# download the latest release
curl -L https://github.com/voku/PHPDoctor/releases/latest/download/phpdoctor.phar -o phpdoctor.phar
chmod +x phpdoctor.phar
php phpdoctor.phar analyse --helpTo build locally, install humbug/box and run:
# install production dependencies only
composer install --no-dev --optimize-autoloader
# download box (or install via phive: phive install humbug/box)
curl -L https://github.com/box-project/box/releases/latest/download/box.phar -o box.phar
# compile the PHAR
php -d phar.readonly=0 box.phar compile --config=box.json.distFor support and donations please visit Github | Issues | PayPal | Patreon.
For status updates and release announcements please visit Releases | Twitter | Patreon.
For professional support please contact me.
- Thanks to GitHub (Microsoft) for hosting the code and a good infrastructure including Issues-Management, etc.
- Thanks to IntelliJ as they make the best IDEs for PHP and they gave me an open source license for PhpStorm!
- Thanks to GitHub Actions for the awesome CI/CD platform!
- Thanks to StyleCI for the simple but powerful code style check.
- Thanks to PHPStan && Psalm for really great Static analysis tools and for discover bugs in the code!