The Jetpack monorepo uses Phan to perform static code analysis. While PHPCS can catch some surface-level issues and enforces coding standards, static analysis does a deep analysis of the code flows across the whole project, helping to identify problems like unused variables, dead code, and mismatched data types. Catching these issues early prevents bugs from making it into production.
Currently static analysis runs on all commits pushed to the monorepo.
Configuration for a project resides in the .phan/config.php
within the project, which should generally build on top of the .phan/config.base.php
from the monorepo root. A baseline file also resides at .phan/baseline.php
to allow for incremental fixing of errors.
FAQs
How can I fix my types?
Where you can’t directly declare the types in PHP, you can use PHPDoc tags to declare what types things are supposed to be:
@var
on class properties.@param
,@return
, and@throws
on functions and methods.
You can also use @phan-var
, @phan-param
, and so on if using the unprefixed tags would confuse other things.
Many of the existing type errors Phan is raising can be fixed by improving the PHPDoc. For example, code may be documented as @var WP_Error
, which is being interpreted as Some\Namespace\WP_Error
; this should instead be documented as @var \WP_Error
.
Inline documentation like /** @var MyClass $var */
will not work, as php-ast
does not preserve these comments. Phan can infer from if ( $var instanceof MyClass ) { ... }
that $var
is a MyClass
inside the body of the if
, which may be a beneficial check to add. Or, if you know for sure the type in a specific instance, Phan allows for using no-op string literal statements like '@var MyClass $var';
directly after the assignment to $var
.
How do I deal with false positives?
First, be sure it’s really a false positive. If it really is a false positive, Phan recognizes inline comments like // @phan-suppress-current-line PhanUndeclaredVariable
or // @phan-suppress-next-line PhanUndeclaredVariable, PhanUndeclaredFunction
to silence issues on a particular line.
You can also use @phan-suppress
in the doc block for the nearest enclosing class, function, or method to suppress issues within that scope, or @phan-file-suppress
to suppress issues for an entire file. Use these sparingly so as to not accidentally ignore issues other than the one you intend.
GitHub keeps reporting new errors
GitHub limits each CI check to 10 inline annotations. If you think there might be more, you’d have to look at the log output for the check run or run Phan locally (see below).
Running Phan locally
Phan in the monorepo should be run locally via Jetpack’s CLI tool as jetpack phan
. Note that Phan soft-requires the PHP ast extension; while on Linux installing this is often as easy as sudo apt-get install php8.2-ast
, some Mac users have reported needing further steps.
Set up PHP’s AST extension
You can check whether the ast
extension is already installed in your environment by running php --ri ast
. If it prints something like this, you should be good (unless you need a newer version; see Phan’s README for version requirements):
ast support => enabled
extension version => 1.1.1 AST version => Current version is 90.
All versions (including experimental): {50, 60, 70, 80, 85, 90, 100}
Instructions for Mac users
This assumes you have PHP installed via Homebrew (e.g. you’ve done brew install php@8.2
).
- You may need to
brew install pkg-config zlib
to install some necessary dependencies. - Update the list of available extensions:
pecl channel-update pecl.php.net
- Build the extension:
pecl install ast
- If the build process fails due to mkdir errors with the pecl directory, you might try
mkdir -p /opt/homebrew/lib/php/pecl
and running the install again.
- If the build process fails due to mkdir errors with the pecl directory, you might try
- You may also need to tell PHP where to find the newly-installed extension.
- Run
pecl config-get ext_dir
to find where pecl installs extensions. - Run
php -r 'echo ini_get( "extension_dir" ) . "\n";'
to find where PHP currently expects extensions to live. - If those are the same, great! If not, you have two options:
- If PHP’s current directory is empty, you could find your
php.ini
file (php --ini
) and changeextension_dir
to pecl’s location. - Or else, pecl probably added
extension=ast.so
to an ini file somewhere. You could change theast.so
value to be the full path inside pecl’s directory.
- If PHP’s current directory is empty, you could find your
- Run
If you can’t install the ast
extension, you can still run Phan with the --allow-polyfill-parser
option, but note that this may cause false positives and cannot be used to update baseline files. Alternatively, you can run Phan inside the Docker development environment.