Difference between revisions of "Testing"

From Freephile Wiki
Jump to navigation Jump to search
(3 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
Testing is software development.   
 
Testing is software development.   
  
Software development is writing code. Testing makes sure the code actually works, so in a nutshell: Testing is software development :-)
+
Software development is writing code. Testing makes sure the code actually works, so in a nutshell: '''Testing is software development''' :-)
  
Phan is a static analyzer for PHP. [https://github.com/phan/phan Phan project on GitHub] It will help you write better PHP code. You'll need the [https://github.com/nikic/php-ast Abstract Syntax Tree] PHP extension.  You can read a [https://github.com/phan/phan/wiki/Tutorial-for-Analyzing-a-Large-Sloppy-Code-Base tutorial for how to get Phan working in your project]
+
==Phan==
 +
Phan is a '''[[wp:Static program analysis|static analyzer]]''' for PHP. It will help you write better PHP code. Please note that your source code  To use it, you'll need to install the [https://github.com/nikic/php-ast Abstract Syntax Tree] PHP extension.  See the [https://github.com/phan/phan/wiki/Tutorial-for-Analyzing-a-Large-Sloppy-Code-Base tutorial for analyzing a large sloppy codebase]
  
The MediaWiki project uses Phan. See the article [[mw:Continuous_integration/Phan|Continuous_integration/Phan]]
+
[https://github.com/phan/phan Phan project on GitHub]  
  
==Links==
 
  
#https://github.com/wikimedia/mediawiki-tools-phan
+
The [[MediaWiki]] project uses Phan in its [[Continuous Integration]].  
#https://github.com/phan/phan
 
#https://www.mediawiki.org/wiki/Continuous_integration/Entry_points
 
#https://www.mediawiki.org/wiki/Continuous_integration/Phan
 
#https://www.mediawiki.org/wiki/Best_practices_for_extensions#File_structure
 
#https://github.com/nikic/php-ast
 
#https://github.com/phan/phan/wiki/Getting-Started
 
#https://github.com/phan/phan/blob/v5/internal/CLI-HELP.md
 
  
==Static Analysis of MediaWiki==
+
===Links===
 +
 
 +
#[https://github.com/wikimedia/mediawiki-tools-phan mediawiki-tools-phan] on github
 +
#[https://github.com/phan/phan phan/phan] on github
 +
#[https://github.com/nikic/php-ast nikic/php-ast] on github
 +
#Phan [https://github.com/phan/phan/wiki/Getting-Started Getting-Started]
 +
#Phan [https://github.com/phan/phan/blob/v5/internal/CLI-HELP.md CLI-HELP.md]
 +
 
 +
===Static Analysis of MediaWiki===
 
For some current analysis see https://doc.wikimedia.org/mediawiki-core/master/phpmetrics/complexity.html
 
For some current analysis see https://doc.wikimedia.org/mediawiki-core/master/phpmetrics/complexity.html
  
The on-wiki documentation and even the upstream projects do not exactly provide a usable guide for '''MediaWiki extension''' developers to actually use Phan. If you download MediaWiki and composer update (to get dev dependencies) and also install PHP-AST, then you should be able to run composer phan or ./vendor/bin/phan -p . But, that analyzes the entire MediaWiki codebase, and does '''not''' analyze your extension (unless you specifically add a proper .phan/config.php file to your extension).
+
#[https://www.mediawiki.org/wiki/Continuous_integration/Entry_points Continuous_integration/Entry_points]
 +
#[https://www.mediawiki.org/wiki/Continuous_integration/Phan Continuous_integration/Phan]
 +
#[[mediawikiwiki:Continuous_integration/Tutorials/Add_phan_to_a_MediaWiki_extension|Continuous_integration/Tutorials/Add_phan_to_a_MediaWiki_extension]]
 +
#[https://www.mediawiki.org/wiki/Best_practices_for_extensions#File_structure Best_practices_for_extensions#File_structure]
 +
 
 +
The on-wiki documentation (at MediaWiki.org) and even the upstream projects do not exactly provide a usable guide for MediaWiki implementors to use Phan on an extensive codebase ('''ie. "my whole wiki")'''. Instead, the documentation describes how '''MediaWiki extension''' developers can use Phan by incorporating their code into the larger configuration of MediaWiki Continuous Integration. If you download MediaWiki and composer update (to get dev dependencies) and also install PHP-AST, then you should be able to run <code>composer phan</code> or <code>./vendor/bin/phan -p .</code> But, that analyzes the entire MediaWiki codebase (using a lot of RAM and time), and does '''not''' analyze random extensions (found on client's wiki instance) unless those extensions already have their own <code>./phan/config.php</code>
  
[[Mark Hershberger]] provides an example of what that might look like in his CommentStreams configuration<syntaxhighlight lang="php">
+
The traditional form of that<ref>https://codesearch.wmcloud.org/things/?q=exclude_analysis_directory_list&files=.phan%2Fconfig.php&excludeFiles=&repos=</ref>, for an extension named "MyExtension", which has dependencies on the Echo and SocialProfile extension, is<syntaxhighlight lang="php">
<?php
 
$cfg = require __DIR__ . '/../vendor/mediawiki/mediawiki-phan-config/src/config.php';
 
$extensions = [ "Echo", "SocialProfile" ];
 
// Assume this extension exists in a directory with a bunch of other extensions that may, or may not be, $IP/extensions
 
$extDir = realpath( __DIR__ . "/../.." );
 
$dirList = array_filter(
 
array_map( fn ( $dir ): string => "$extDir/$dir", $extensions ),
 
fn ( $dir ): bool => is_dir( $dir )
 
);
 
$cfg['directory_list'] = array_merge( $cfg['directory_list'] ?? [], $dirList );
 
$cfg['exclude_analysis_directory_list'] = array_merge(
 
$cfg['exclude_analysis_directory_list'] ?? [], $dirList
 
);
 
$cfg['suppress_issue_types'][] = 'PhanUndeclaredConstant';
 
return $cfg;
 
</syntaxhighlight>The more traditional form of that<ref>https://codesearch.wmcloud.org/things/?q=exclude_analysis_directory_list&files=.phan%2Fconfig.php&excludeFiles=&repos=</ref> is<syntaxhighlight lang="php">
 
 
$cfg = require __DIR__ . '/../vendor/mediawiki/mediawiki-phan-config/src/config.php';
 
$cfg = require __DIR__ . '/../vendor/mediawiki/mediawiki-phan-config/src/config.php';
  
Line 58: Line 48:
  
 
return $cfg;
 
return $cfg;
</syntaxhighlight>But why is the normal pattern to include directories and exclude those same directories? The answer ''seems'' to be that you include 'dependencies' for class definition, but do not warn about issues outside the limits of your own extension.
+
</syntaxhighlight>The reason the normal pattern is to include directories and exclude those same directories is that you include 'dependencies' for class definitions etc. (symbol discovery), but do not warn about issues outside the limits of your own MyExtension extension.
 +
 
 +
{{Ambox|
 +
|text=If your Extension '''does''' have dependencies on other extensions, '''and''' you are hosting your code in gerrit for automated CI checks and fixes (you should), you must create an entry in the so-called [https://gerrit.wikimedia.org/r/plugins/gitiles/integration/config/+/refs/heads/master/zuul/parameter_functions.py#558 parameter-functions.py] to declare those dependencies.}}
 +
 
 +
====MediaWiki Phan Config====
 +
The bigger (unanswered) question is '''what does mediawiki-phan-config do?''' What is the compiled and complete configuration that you are "running" against your codebase?
 +
 
 +
<br />
 +
 
 +
{{Collapsible
 +
|visible_text=Show the full configuration for MediaWiki phan
 +
|collapsed_content=
 +
 
 +
In <code>.phan/config.php</code> I simply added <syntaxhighlight lang="php">print_r( $cfg ); exit();</syntaxhighlight> just before the 'return' at the end of the file. Then I ran <code>composer phan</code> to invoke it from my shell and display the object variable.
 +
<syntaxhighlight lang="php" line="1">
 +
Array
 +
(
 +
    [backward_compatibility_checks] =>
 +
    [parent_constructor_required] => Array
 +
        (
 +
        )
 +
 
 +
    [quick_mode] =>
 +
    [analyze_signature_compatibility] => 1
 +
    [ignore_undeclared_variables_in_global_scope] => 1
 +
    [read_type_annotations] => 1
 +
    [disable_suppression] =>
 +
    [dump_ast] =>
 +
    [dump_signatures_file] =>
 +
    [processes] => 1
 +
    [whitelist_issue_types] => Array
 +
        (
 +
        )
 +
 
 +
    [markdown_issue_messages] =>
 +
    [generic_types_enabled] => 1
 +
    [plugins] => Array
 +
        (
 +
            [0] => PregRegexCheckerPlugin
 +
            [1] => UnusedSuppressionPlugin
 +
            [2] => DuplicateExpressionPlugin
 +
            [3] => LoopVariableReusePlugin
 +
            [4] => RedundantAssignmentPlugin
 +
            [5] => UnreachableCodePlugin
 +
            [6] => SimplifyExpressionPlugin
 +
            [7] => DuplicateArrayKeyPlugin
 +
            [8] => UseReturnValuePlugin
 +
            [9] => AddNeverReturnTypePlugin
 +
            [10] => /opt/htdocs/mediawiki/vendor/mediawiki/mediawiki-phan-config/src/../../phan-taint-check-plugin/MediaWikiSecurityCheckPlugin.php
 +
        )
 +
 
 +
    [plugin_config] => Array
 +
        (
 +
        )
 +
 
 +
    [file_list] => Array
 +
        (
 +
            [0] => .phan/stubs/password.php
 +
            [1] => .phan/stubs/Socket.php
 +
            [2] => .phan/stubs/WeakMap.php
 +
            [3] => includes/Defines.php
 +
            [4] => tests/phpunit/MediaWikiIntegrationTestCase.php
 +
            [5] => tests/phpunit/includes/TestUser.php
 +
        )
 +
 
 +
    [exclude_file_list] => Array
 +
        (
 +
            [0] => vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Methods/MethodDeclarationUnitTest.inc
 +
            [1] => vendor/php-parallel-lint/php-parallel-lint/src/polyfill.php
 +
        )
 +
 
 +
    [exclude_analysis_directory_list] => Array
 +
        (
 +
            [0] => vendor/
 +
            [1] => .phan/
 +
            [2] => tests/phpunit/
 +
            [3] => includes/config-vars.php
 +
            [4] => includes/composer/
 +
            [5] => maintenance/language/
 +
            [6] => includes/libs/jsminplus.php
 +
            [7] => includes/libs/objectcache/utils/MemcachedClient.php
 +
            [8] => includes/PHPVersionCheck.php
 +
        )
 +
 
 +
    [exclude_file_regex] => @vendor/((composer/installers|php-parallel-lint/php-console-color|php-parallel-lint/php-console-highlighter|php-parallel-lint/php-parallel-lint|mediawiki/mediawiki-codesniffer|microsoft/tolerant-php-parser|phan/phan|phpunit/php-code-coverage|squizlabs/php_codesniffer|[^/]+/[^/]+/\.phan)|.*/[Tt]ests?)/@
 +
    [minimum_severity] => 0
 +
    [allow_missing_properties] =>
 +
    [null_casts_as_any_type] =>
 +
    [scalar_implicit_cast] =>
 +
    [dead_code_detection] =>
 +
    [dead_code_detection_prefer_false_negative] => 1
 +
    [progress_bar] =>
 +
    [enable_class_alias_support] =>
 +
    [redundant_condition_detection] => 1
 +
    [minimum_target_php_version] => 7.4.3
 +
    [target_php_version] => 8.1
 +
    [directory_list] => Array
 +
        (
 +
            [0] => includes/
 +
            [1] => languages/
 +
            [2] => maintenance/
 +
            [3] => mw-config/
 +
            [4] => resources/
 +
            [5] => vendor/
 +
            [6] => tests/common/
 +
            [7] => tests/parser/
 +
            [8] => tests/phpunit/mocks/
 +
        )
 +
 
 +
    [suppress_issue_types] => Array
 +
        (
 +
            [0] => PhanDeprecatedFunction
 +
            [1] => PhanDeprecatedClass
 +
            [2] => PhanDeprecatedClassConstant
 +
            [3] => PhanDeprecatedFunctionInternal
 +
            [4] => PhanDeprecatedInterface
 +
            [5] => PhanDeprecatedProperty
 +
            [6] => PhanDeprecatedTrait
 +
            [7] => PhanUnreferencedUseNormal
 +
            [8] => PhanUnreferencedUseFunction
 +
            [9] => PhanUnreferencedUseConstant
 +
            [10] => PhanDuplicateUseNormal
 +
            [11] => PhanDuplicateUseFunction
 +
            [12] => PhanDuplicateUseConstant
 +
            [13] => PhanUseNormalNoEffect
 +
            [14] => PhanUseNormalNamespacedNoEffect
 +
            [15] => PhanUseFunctionNoEffect
 +
            [16] => PhanUseConstantNoEffect
 +
            [17] => PhanDeprecatedCaseInsensitiveDefine
 +
            [18] => PhanAccessClassConstantInternal
 +
            [19] => PhanAccessClassInternal
 +
            [20] => PhanAccessConstantInternal
 +
            [21] => PhanAccessMethodInternal
 +
            [22] => PhanAccessPropertyInternal
 +
            [23] => PhanParamNameIndicatingUnused
 +
            [24] => PhanParamNameIndicatingUnusedInClosure
 +
            [25] => PhanProvidingUnusedParameter
 +
            [26] => PhanPluginMixedKeyNoKey
 +
            [27] => SecurityCheck-LikelyFalsePositive
 +
            [28] => SecurityCheck-PHPSerializeInjection
 +
            [29] => PhanPluginDuplicateExpressionAssignmentOperation
 +
            [30] => PhanPluginDuplicateExpressionAssignmentOperation
 +
        )
 +
 
 +
    [globals_type_map] => Array
 +
        (
 +
            [wgContLang] => \Language
 +
            [wgParser] => \Parser
 +
            [wgTitle] => \Title
 +
            [wgMemc] => \BagOStuff
 +
            [wgUser] => \User
 +
            [wgConf] => \SiteConfiguration
 +
            [wgLang] => \Language
 +
            [wgOut] => OutputPage
 +
            [wgRequest] => \WebRequest
 +
            [IP] => string
 +
            [wgGalleryOptions] => array
 +
            [wgDummyLanguageCodes] => string[]
 +
            [wgNamespaceProtection] => array<int,string|string[]>
 +
            [wgNamespaceAliases] => array<string,int>
 +
            [wgLockManagers] => array[]
 +
            [wgForeignFileRepos] => array[]
 +
            [wgDefaultUserOptions] => array
 +
            [wgSkipSkins] => string[]
 +
            [wgLogTypes] => string[]
 +
            [wgLogNames] => array<string,string>
 +
            [wgLogHeaders] => array<string,string>
 +
            [wgLogActionsHandlers] => array<string,class-string>
 +
            [wgPasswordPolicy] => array<string,array<string,string|array>>
 +
            [wgVirtualRestConfig] => array<string,array>
 +
            [wgWANObjectCaches] => array[]
 +
            [wgLocalInterwikis] => string[]
 +
            [wgDebugLogGroups] => string|false|array{destination:string,sample?:int,level:int}
 +
            [wgCookiePrefix] => string|false
 +
            [wgExtraNamespaces] => string[]
 +
        )
 +
 
 +
    [analyzed_file_extensions] => Array
 +
        (
 +
            [0] => php
 +
            [1] => inc
 +
        )
 +
 
 +
    [autoload_internal_extension_signatures] => Array
 +
        (
 +
            [dom] => .phan/internal_stubs/dom.phan_php
 +
            [excimer] => .phan/internal_stubs/excimer.php
 +
            [imagick] => .phan/internal_stubs/imagick.phan_php
 +
            [memcached] => .phan/internal_stubs/memcached.phan_php
 +
            [oci8] => .phan/internal_stubs/oci8.phan_php
 +
            [pcntl] => .phan/internal_stubs/pcntl.phan_php
 +
            [pgsql] => .phan/internal_stubs/pgsql.phan_php
 +
            [redis] => .phan/internal_stubs/redis.phan_php
 +
            [sockets] => .phan/internal_stubs/sockets.phan_php
 +
            [sqlsrv] => .phan/internal_stubs/sqlsrv.phan_php
 +
            [tideways] => .phan/internal_stubs/tideways.phan_php
 +
            [wikidiff2] => .phan/internal_stubs/wikidiff.php
 +
        )
 +
 
 +
)
 +
 
 +
</syntaxhighlight>
 +
 
 +
}}
 +
 
  
The bigger (unanswered) question is what does mediawiki-phan-config do? What is the compiled and complete configuration that you are "running" against your codebase?
+
MediaWiki Phan Config has a [https://github.com/wikimedia/mediawiki-tools-phan/blob/master/src/ConfigBuilder.php#L8 ConfigBuilder.php] class that is used to build up the project's phan config. The goto file to see how it's configured is '''[https://github.com/wikimedia/mediawiki-tools-phan/blob/master/src/config.php config.php]'''
  
== Plugins ==
+
Phan has a ton of plugins - but their usage in the MediaWiki configuration is not mentioned or described anywhere (that I could find). I found a list in 'base-config-functions' [https://github.com/wikimedia/mediawiki-tools-phan/blob/master/src/base-config-functions.php#L68 mediawiki-tools-phan/blob/master/src/base-config-functions.php#L68], but why you need to read the entire source code to "reverse engineer" what is happening? It's not fun.
Phan ha a ton of plugins - but they don't seem to be used in the MediaWiki configuration. Or are they? It's not obvious to me yet.
 
  
 +
===Phan Plugins===
 
https://github.com/phan/phan/tree/v5/.phan/plugins#2-general-use-plugins
 
https://github.com/phan/phan/tree/v5/.phan/plugins#2-general-use-plugins
  
 
The [https://github.com/phan/phan/wiki/Writing-Plugins-for-Phan writing plugins guide] also describes how they work.
 
The [https://github.com/phan/phan/wiki/Writing-Plugins-for-Phan writing plugins guide] also describes how they work.
  
== Check code for compatibility with a particular PHP version ==
+
===Check code for compatibility with a particular PHP version===
 
One major reason I wanted to use phan was to upgrade a whole codebase, and check its compatibility with an upgraded PHP (moving from 7.4 to 8.1). There is at least one caveat to doing this: You should be running php 8.1 in order to check code for compatibility with 8.1 You can use phan with the config setting of  <code>target_php_version</code><ref>https://github.com/phan/phan/wiki/Phan-Config-Settings#analysis-of-a-php-version</ref>
 
One major reason I wanted to use phan was to upgrade a whole codebase, and check its compatibility with an upgraded PHP (moving from 7.4 to 8.1). There is at least one caveat to doing this: You should be running php 8.1 in order to check code for compatibility with 8.1 You can use phan with the config setting of  <code>target_php_version</code><ref>https://github.com/phan/phan/wiki/Phan-Config-Settings#analysis-of-a-php-version</ref>
  
== Phan with VSCode ==
+
===Phan with VSCode===
 
https://github.com/phan/phan/wiki/Editor-Support supposed to just work (with the plugin). But after I installed the plugin, it was not producing any hint of working or any errors.
 
https://github.com/phan/phan/wiki/Editor-Support supposed to just work (with the plugin). But after I installed the plugin, it was not producing any hint of working or any errors.
  
== Phan checks ==
+
===Phan checks===
 
There are over 1,000 things that phan tests its own code against
 
There are over 1,000 things that phan tests its own code against
  
Line 83: Line 278:
 
<br />
 
<br />
  
== Other Static Analysis tools for PHP ==
+
==Other Static Analysis tools for PHP==
  
=== PHPStan ===
+
===PHPStan===
 
https://phpstan.org/
 
https://phpstan.org/
 +
 +
PHPStan seems more polished (perhaps because it's commercial and has a 'pro' version that adds a GUI) whereas phan is the original PHP static analysis tool Rasmus Ledorf uses.
 +
 +
Adding a configuration file for your MediaWiki extension is straightforward and would look like this:<syntaxhighlight lang="yaml">
 +
parameters:
 +
level: 1
 +
paths:
 +
- src
 +
- tests
 +
scanDirectories:
 +
- ../../includes
 +
- ../../tests/phpunit
 +
- ../../vendor
 +
</syntaxhighlight>
 +
 +
 +
The [https://phpstan.org/user-guide/rule-levels level can be 0 - 9]
 +
 +
The paths are the directories of '''your code.'''
 +
 +
The scanDirectories are additional paths used to discover symbols, but not analyze for errors.
 +
 +
For more advanced usage, see [https://github.com/ProfessionalWiki/Maps/blob/ee88211fadb3573b646cce005383450e96c3054e/phpstan.neon the example of Professional Wiki's Maps extension] which illustrates configuration file includes of a 'baseline'; error message suppression; and directory exclusions of problem code.
  
 
===Psalm===
 
===Psalm===
 
https://psalm.dev/
 
https://psalm.dev/
 +
 +
 +
 +
 +
 +
 +
 +
 +
<references />
  
 
[[Category:Wiki]]
 
[[Category:Wiki]]
Line 99: Line 326:
 
[[Category:Tools]]
 
[[Category:Tools]]
 
[[Category:Continuous Integration]]
 
[[Category:Continuous Integration]]
<references />
 

Revision as of 19:33, 17 February 2024

Testing is software development.

Software development is writing code. Testing makes sure the code actually works, so in a nutshell: Testing is software development :-)

Phan[edit | edit source]

Phan is a static analyzer for PHP. It will help you write better PHP code. Please note that your source code To use it, you'll need to install the Abstract Syntax Tree PHP extension. See the tutorial for analyzing a large sloppy codebase

Phan project on GitHub


The MediaWiki project uses Phan in its Continuous Integration.

Links[edit | edit source]

  1. mediawiki-tools-phan on github
  2. phan/phan on github
  3. nikic/php-ast on github
  4. Phan Getting-Started
  5. Phan CLI-HELP.md

Static Analysis of MediaWiki[edit | edit source]

For some current analysis see https://doc.wikimedia.org/mediawiki-core/master/phpmetrics/complexity.html

  1. Continuous_integration/Entry_points
  2. Continuous_integration/Phan
  3. Continuous_integration/Tutorials/Add_phan_to_a_MediaWiki_extension
  4. Best_practices_for_extensions#File_structure

The on-wiki documentation (at MediaWiki.org) and even the upstream projects do not exactly provide a usable guide for MediaWiki implementors to use Phan on an extensive codebase (ie. "my whole wiki"). Instead, the documentation describes how MediaWiki extension developers can use Phan by incorporating their code into the larger configuration of MediaWiki Continuous Integration. If you download MediaWiki and composer update (to get dev dependencies) and also install PHP-AST, then you should be able to run composer phan or ./vendor/bin/phan -p . But, that analyzes the entire MediaWiki codebase (using a lot of RAM and time), and does not analyze random extensions (found on client's wiki instance) unless those extensions already have their own ./phan/config.php

The traditional form of that[1], for an extension named "MyExtension", which has dependencies on the Echo and SocialProfile extension, is

$cfg = require __DIR__ . '/../vendor/mediawiki/mediawiki-phan-config/src/config.php';

$cfg['directory_list'] = array_merge(
	$cfg['directory_list'],
	[
		'../../extensions/Echo',
		'../../extensions/SocialProfile',
	]
);
$cfg['exclude_analysis_directory_list'] = array_merge(
	$cfg['exclude_analysis_directory_list'],
	[
		'../../extensions/Echo',
		'../../extensions/SocialProfile',
	]
);

return $cfg;

The reason the normal pattern is to include directories and exclude those same directories is that you include 'dependencies' for class definitions etc. (symbol discovery), but do not warn about issues outside the limits of your own MyExtension extension.

MediaWiki Phan Config[edit | edit source]

The bigger (unanswered) question is what does mediawiki-phan-config do? What is the compiled and complete configuration that you are "running" against your codebase?



Show the full configuration for MediaWiki phan

In .phan/config.php I simply added
print_r( $cfg ); exit();
just before the 'return' at the end of the file. Then I ran composer phan to invoke it from my shell and display the object variable.
  1 Array
  2 (
  3     [backward_compatibility_checks] => 
  4     [parent_constructor_required] => Array
  5         (
  6         )
  7 
  8     [quick_mode] => 
  9     [analyze_signature_compatibility] => 1
 10     [ignore_undeclared_variables_in_global_scope] => 1
 11     [read_type_annotations] => 1
 12     [disable_suppression] => 
 13     [dump_ast] => 
 14     [dump_signatures_file] => 
 15     [processes] => 1
 16     [whitelist_issue_types] => Array
 17         (
 18         )
 19 
 20     [markdown_issue_messages] => 
 21     [generic_types_enabled] => 1
 22     [plugins] => Array
 23         (
 24             [0] => PregRegexCheckerPlugin
 25             [1] => UnusedSuppressionPlugin
 26             [2] => DuplicateExpressionPlugin
 27             [3] => LoopVariableReusePlugin
 28             [4] => RedundantAssignmentPlugin
 29             [5] => UnreachableCodePlugin
 30             [6] => SimplifyExpressionPlugin
 31             [7] => DuplicateArrayKeyPlugin
 32             [8] => UseReturnValuePlugin
 33             [9] => AddNeverReturnTypePlugin
 34             [10] => /opt/htdocs/mediawiki/vendor/mediawiki/mediawiki-phan-config/src/../../phan-taint-check-plugin/MediaWikiSecurityCheckPlugin.php
 35         )
 36 
 37     [plugin_config] => Array
 38         (
 39         )
 40 
 41     [file_list] => Array
 42         (
 43             [0] => .phan/stubs/password.php
 44             [1] => .phan/stubs/Socket.php
 45             [2] => .phan/stubs/WeakMap.php
 46             [3] => includes/Defines.php
 47             [4] => tests/phpunit/MediaWikiIntegrationTestCase.php
 48             [5] => tests/phpunit/includes/TestUser.php
 49         )
 50 
 51     [exclude_file_list] => Array
 52         (
 53             [0] => vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Methods/MethodDeclarationUnitTest.inc
 54             [1] => vendor/php-parallel-lint/php-parallel-lint/src/polyfill.php
 55         )
 56 
 57     [exclude_analysis_directory_list] => Array
 58         (
 59             [0] => vendor/
 60             [1] => .phan/
 61             [2] => tests/phpunit/
 62             [3] => includes/config-vars.php
 63             [4] => includes/composer/
 64             [5] => maintenance/language/
 65             [6] => includes/libs/jsminplus.php
 66             [7] => includes/libs/objectcache/utils/MemcachedClient.php
 67             [8] => includes/PHPVersionCheck.php
 68         )
 69 
 70     [exclude_file_regex] => @vendor/((composer/installers|php-parallel-lint/php-console-color|php-parallel-lint/php-console-highlighter|php-parallel-lint/php-parallel-lint|mediawiki/mediawiki-codesniffer|microsoft/tolerant-php-parser|phan/phan|phpunit/php-code-coverage|squizlabs/php_codesniffer|[^/]+/[^/]+/\.phan)|.*/[Tt]ests?)/@
 71     [minimum_severity] => 0
 72     [allow_missing_properties] => 
 73     [null_casts_as_any_type] => 
 74     [scalar_implicit_cast] => 
 75     [dead_code_detection] => 
 76     [dead_code_detection_prefer_false_negative] => 1
 77     [progress_bar] => 
 78     [enable_class_alias_support] => 
 79     [redundant_condition_detection] => 1
 80     [minimum_target_php_version] => 7.4.3
 81     [target_php_version] => 8.1
 82     [directory_list] => Array
 83         (
 84             [0] => includes/
 85             [1] => languages/
 86             [2] => maintenance/
 87             [3] => mw-config/
 88             [4] => resources/
 89             [5] => vendor/
 90             [6] => tests/common/
 91             [7] => tests/parser/
 92             [8] => tests/phpunit/mocks/
 93         )
 94 
 95     [suppress_issue_types] => Array
 96         (
 97             [0] => PhanDeprecatedFunction
 98             [1] => PhanDeprecatedClass
 99             [2] => PhanDeprecatedClassConstant
100             [3] => PhanDeprecatedFunctionInternal
101             [4] => PhanDeprecatedInterface
102             [5] => PhanDeprecatedProperty
103             [6] => PhanDeprecatedTrait
104             [7] => PhanUnreferencedUseNormal
105             [8] => PhanUnreferencedUseFunction
106             [9] => PhanUnreferencedUseConstant
107             [10] => PhanDuplicateUseNormal
108             [11] => PhanDuplicateUseFunction
109             [12] => PhanDuplicateUseConstant
110             [13] => PhanUseNormalNoEffect
111             [14] => PhanUseNormalNamespacedNoEffect
112             [15] => PhanUseFunctionNoEffect
113             [16] => PhanUseConstantNoEffect
114             [17] => PhanDeprecatedCaseInsensitiveDefine
115             [18] => PhanAccessClassConstantInternal
116             [19] => PhanAccessClassInternal
117             [20] => PhanAccessConstantInternal
118             [21] => PhanAccessMethodInternal
119             [22] => PhanAccessPropertyInternal
120             [23] => PhanParamNameIndicatingUnused
121             [24] => PhanParamNameIndicatingUnusedInClosure
122             [25] => PhanProvidingUnusedParameter
123             [26] => PhanPluginMixedKeyNoKey
124             [27] => SecurityCheck-LikelyFalsePositive
125             [28] => SecurityCheck-PHPSerializeInjection
126             [29] => PhanPluginDuplicateExpressionAssignmentOperation
127             [30] => PhanPluginDuplicateExpressionAssignmentOperation
128         )
129 
130     [globals_type_map] => Array
131         (
132             [wgContLang] => \Language
133             [wgParser] => \Parser
134             [wgTitle] => \Title
135             [wgMemc] => \BagOStuff
136             [wgUser] => \User
137             [wgConf] => \SiteConfiguration
138             [wgLang] => \Language
139             [wgOut] => OutputPage
140             [wgRequest] => \WebRequest
141             [IP] => string
142             [wgGalleryOptions] => array
143             [wgDummyLanguageCodes] => string[]
144             [wgNamespaceProtection] => array<int,string|string[]>
145             [wgNamespaceAliases] => array<string,int>
146             [wgLockManagers] => array[]
147             [wgForeignFileRepos] => array[]
148             [wgDefaultUserOptions] => array
149             [wgSkipSkins] => string[]
150             [wgLogTypes] => string[]
151             [wgLogNames] => array<string,string>
152             [wgLogHeaders] => array<string,string>
153             [wgLogActionsHandlers] => array<string,class-string>
154             [wgPasswordPolicy] => array<string,array<string,string|array>>
155             [wgVirtualRestConfig] => array<string,array>
156             [wgWANObjectCaches] => array[]
157             [wgLocalInterwikis] => string[]
158             [wgDebugLogGroups] => string|false|array{destination:string,sample?:int,level:int}
159             [wgCookiePrefix] => string|false
160             [wgExtraNamespaces] => string[]
161         )
162 
163     [analyzed_file_extensions] => Array
164         (
165             [0] => php
166             [1] => inc
167         )
168 
169     [autoload_internal_extension_signatures] => Array
170         (
171             [dom] => .phan/internal_stubs/dom.phan_php
172             [excimer] => .phan/internal_stubs/excimer.php
173             [imagick] => .phan/internal_stubs/imagick.phan_php
174             [memcached] => .phan/internal_stubs/memcached.phan_php
175             [oci8] => .phan/internal_stubs/oci8.phan_php
176             [pcntl] => .phan/internal_stubs/pcntl.phan_php
177             [pgsql] => .phan/internal_stubs/pgsql.phan_php
178             [redis] => .phan/internal_stubs/redis.phan_php
179             [sockets] => .phan/internal_stubs/sockets.phan_php
180             [sqlsrv] => .phan/internal_stubs/sqlsrv.phan_php
181             [tideways] => .phan/internal_stubs/tideways.phan_php
182             [wikidiff2] => .phan/internal_stubs/wikidiff.php
183         )
184 
185 )



MediaWiki Phan Config has a ConfigBuilder.php class that is used to build up the project's phan config. The goto file to see how it's configured is config.php

Phan has a ton of plugins - but their usage in the MediaWiki configuration is not mentioned or described anywhere (that I could find). I found a list in 'base-config-functions' mediawiki-tools-phan/blob/master/src/base-config-functions.php#L68, but why you need to read the entire source code to "reverse engineer" what is happening? It's not fun.

Phan Plugins[edit | edit source]

https://github.com/phan/phan/tree/v5/.phan/plugins#2-general-use-plugins

The writing plugins guide also describes how they work.

Check code for compatibility with a particular PHP version[edit | edit source]

One major reason I wanted to use phan was to upgrade a whole codebase, and check its compatibility with an upgraded PHP (moving from 7.4 to 8.1). There is at least one caveat to doing this: You should be running php 8.1 in order to check code for compatibility with 8.1 You can use phan with the config setting of target_php_version[2]

Phan with VSCode[edit | edit source]

https://github.com/phan/phan/wiki/Editor-Support supposed to just work (with the plugin). But after I installed the plugin, it was not producing any hint of working or any errors.

Phan checks[edit | edit source]

There are over 1,000 things that phan tests its own code against

https://github.com/phan/phan/tree/v5/tests

https://github.com/phan/phan/tree/v5/tests/files/src

Other Static Analysis tools for PHP[edit | edit source]

PHPStan[edit | edit source]

https://phpstan.org/

PHPStan seems more polished (perhaps because it's commercial and has a 'pro' version that adds a GUI) whereas phan is the original PHP static analysis tool Rasmus Ledorf uses.

Adding a configuration file for your MediaWiki extension is straightforward and would look like this:

parameters:
	level: 1
	paths:
		- src
		- tests
	scanDirectories:
		- ../../includes
		- ../../tests/phpunit
		- ../../vendor


The level can be 0 - 9

The paths are the directories of your code.

The scanDirectories are additional paths used to discover symbols, but not analyze for errors.

For more advanced usage, see the example of Professional Wiki's Maps extension which illustrates configuration file includes of a 'baseline'; error message suppression; and directory exclusions of problem code.

Psalm[edit | edit source]

https://psalm.dev/