diff --git a/.travis.yml b/.travis.yml
index 0cff50a3adb27d1e3fdb0a7049086515fe1744d0..3f29a999060742af38cf137c7df0f0efbf055cc4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,6 +10,7 @@ cache:
 jobs:
   fast_finish: true
   include:
+    # Support PHP 7.0 because that is the minimum requirement of Drupal 8 core.
     - php: 7.0
       dist: xenial
     - php: 7.1
@@ -20,6 +21,7 @@ jobs:
       dist: bionic
     - php: 7.4
       dist: bionic
+      env: PHPSTAN=1
 
 before_install:
   # Speed up build time by disabling Xdebug when its not needed.
@@ -40,3 +42,5 @@ script:
   # Ensure that the DrupalPractice standard can be invoked standalone and the
   # auto-loading of abstract classes works.
   - ./vendor/bin/phpcs -p --standard=coder_sniffer/DrupalPractice coder_sniffer/DrupalPractice/Test/good/ --ignore=coder_sniffer/DrupalPractice/Test/good/GoodUnitTest.php
+   # We cannot add PHPStan to composer.json because it cannot be installed in PHP 7.0.
+  - if [[ $PHPSTAN == "1" ]]; then composer require --dev phpstan/phpstan && ./vendor/bin/phpstan analyse; fi
diff --git a/coder_sniffer/Drupal/Sniffs/Arrays/DisallowLongArraySyntaxSniff.php b/coder_sniffer/Drupal/Sniffs/Arrays/DisallowLongArraySyntaxSniff.php
index 6fe8f2aff2c60313c51ca6b6b762c1e84dfb6acf..356e36284c20c2c0cc0443111211d7355b42487e 100644
--- a/coder_sniffer/Drupal/Sniffs/Arrays/DisallowLongArraySyntaxSniff.php
+++ b/coder_sniffer/Drupal/Sniffs/Arrays/DisallowLongArraySyntaxSniff.php
@@ -41,7 +41,7 @@ class DisallowLongArraySyntaxSniff extends GenericDisallowLongArraySyntaxSniff
             return ($phpcsFile->numTokens + 1);
         }
 
-        return parent::process($phpcsFile, $stackPtr);
+        parent::process($phpcsFile, $stackPtr);
 
     }//end process()
 
diff --git a/coder_sniffer/Drupal/Sniffs/Commenting/FileCommentSniff.php b/coder_sniffer/Drupal/Sniffs/Commenting/FileCommentSniff.php
index ecd340b7fab0e50c0be61a7cf95762fb5059bbcd..f2196eb04636f364acabefdb014b10ca14512b89 100644
--- a/coder_sniffer/Drupal/Sniffs/Commenting/FileCommentSniff.php
+++ b/coder_sniffer/Drupal/Sniffs/Commenting/FileCommentSniff.php
@@ -64,8 +64,6 @@ class FileCommentSniff implements Sniff
      */
     public function process(File $phpcsFile, $stackPtr)
     {
-        $this->currentFile = $phpcsFile;
-
         $tokens       = $phpcsFile->getTokens();
         $commentStart = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true);
 
diff --git a/coder_sniffer/Drupal/Sniffs/Semantics/FunctionAliasSniff.php b/coder_sniffer/Drupal/Sniffs/Semantics/FunctionAliasSniff.php
index 5f44eb5b65730c8c83d3924b4d478a0f8050151e..3fa1f3c18e2c6389b5554a0159f5969ee52144c7 100644
--- a/coder_sniffer/Drupal/Sniffs/Semantics/FunctionAliasSniff.php
+++ b/coder_sniffer/Drupal/Sniffs/Semantics/FunctionAliasSniff.php
@@ -94,42 +94,25 @@ class FunctionAliasSniff extends FunctionCall
         'msql_selectdb'              => 'msql_select_db',
         'msql_tablename'             => 'msql_result',
         'mssql_affected_rows'        => 'sybase_affected_rows',
-        'mssql_affected_rows'        => 'sybase_affected_rows',
-        'mssql_close'                => 'sybase_close',
         'mssql_close'                => 'sybase_close',
         'mssql_connect'              => 'sybase_connect',
-        'mssql_connect'              => 'sybase_connect',
         'mssql_data_seek'            => 'sybase_data_seek',
-        'mssql_data_seek'            => 'sybase_data_seek',
-        'mssql_fetch_array'          => 'sybase_fetch_array',
         'mssql_fetch_array'          => 'sybase_fetch_array',
         'mssql_fetch_field'          => 'sybase_fetch_field',
-        'mssql_fetch_field'          => 'sybase_fetch_field',
-        'mssql_fetch_object'         => 'sybase_fetch_object',
         'mssql_fetch_object'         => 'sybase_fetch_object',
         'mssql_fetch_row'            => 'sybase_fetch_row',
-        'mssql_fetch_row'            => 'sybase_fetch_row',
-        'mssql_field_seek'           => 'sybase_field_seek',
         'mssql_field_seek'           => 'sybase_field_seek',
         'mssql_free_result'          => 'sybase_free_result',
-        'mssql_free_result'          => 'sybase_free_result',
-        'mssql_get_last_message'     => 'sybase_get_last_message',
         'mssql_get_last_message'     => 'sybase_get_last_message',
         'mssql_min_client_severity'  => 'sybase_min_client_severity',
         'mssql_min_error_severity'   => 'sybase_min_error_severity',
         'mssql_min_message_severity' => 'sybase_min_message_severity',
         'mssql_min_server_severity'  => 'sybase_min_server_severity',
         'mssql_num_fields'           => 'sybase_num_fields',
-        'mssql_num_fields'           => 'sybase_num_fields',
-        'mssql_num_rows'             => 'sybase_num_rows',
         'mssql_num_rows'             => 'sybase_num_rows',
         'mssql_pconnect'             => 'sybase_pconnect',
-        'mssql_pconnect'             => 'sybase_pconnect',
-        'mssql_query'                => 'sybase_query',
         'mssql_query'                => 'sybase_query',
         'mssql_result'               => 'sybase_result',
-        'mssql_result'               => 'sybase_result',
-        'mssql_select_db'            => 'sybase_select_db',
         'mssql_select_db'            => 'sybase_select_db',
         'mysql'                      => 'mysql_db_query',
         'mysql_createdb'             => 'mysql_create_db',
@@ -153,7 +136,6 @@ class FunctionAliasSniff extends FunctionCall
         'oci8assign'                 => 'ocicollassign',
         'oci8assignelem'             => 'ocicollassignelem',
         'oci8close'                  => 'ocicloselob',
-        'oci8free'                   => 'ocifreecoll',
         'oci8free'                   => 'ocifreedesc',
         'oci8getelem'                => 'ocicollgetelem',
         'oci8load'                   => 'ociloadlob',
diff --git a/composer.json b/composer.json
index 53f3f23234138b59297f69b4f12a91f472147e86..30e33a069d00a56dc03433d0cb3edf79383a53eb 100644
--- a/composer.json
+++ b/composer.json
@@ -20,7 +20,7 @@
         "symfony/yaml": ">=2.0.5"
     },
     "autoload": {
-        "psr-0": {
+        "psr-4": {
             "Drupal\\": "coder_sniffer/Drupal/",
             "DrupalPractice\\": "coder_sniffer/DrupalPractice/"
         }
diff --git a/phpstan.neon b/phpstan.neon
new file mode 100644
index 0000000000000000000000000000000000000000..bf7f8708a4bc7ffa55ce27dc9ea7144b8443be07
--- /dev/null
+++ b/phpstan.neon
@@ -0,0 +1,28 @@
+parameters:
+    level: 0
+    paths:
+        - coder_sniffer/Drupal/Sniffs
+    autoload_files:
+        - coder_sniffer/Drupal/Test/phpunit-bootstrap.php
+    ignoreErrors:
+        # Already fixed in PHP_CodeSniffer, remove once 3.5.4 is released.
+        -
+            count: 3
+            message: '~^Cannot unset offset~'
+            path: %currentWorkingDirectory%/coder_sniffer/Drupal/Sniffs/Formatting/MultipleStatementAlignmentSniff.php
+        # PHPStan does not support variable variables, see https://github.com/phpstan/phpstan/issues/2810
+        -
+            count: 3
+            message: '~^Undefined variable: \$value[123]$~'
+            path: %currentWorkingDirectory%/coder_sniffer/Drupal/Sniffs/InfoFiles/ClassFilesSniff.php
+        -
+            count: 3
+            message: '~^Undefined variable: \$value[123]$~'
+            path: %currentWorkingDirectory%/coder_sniffer/Drupal/Sniffs/InfoFiles/DuplicateEntrySniff.php
+        # We don't want to introduce abstract methods for the 2 calls because
+        # the class is used in different ways where those methods are not
+        # always necessary for implementors.
+        -
+            count: 2
+            message: '~^Call to an undefined method Drupal\\Sniffs\\Semantics\\FunctionCall::(registerFunctionNames|processFunctionCall)\(\).$~'
+            path: %currentWorkingDirectory%/coder_sniffer/Drupal/Sniffs/Semantics/FunctionCall.php