Skip to main content

PHPStan's new @not-deprecated annotation

Published on

The PHPStan 1.10.3 release shipped with a new @not-deprecated annotation! This is a great utility, and I am very thankful to stof for contributing this to PHPStan. This annotation fixes an issue I reported in June 2022 during our massive Drupal 10 readiness initiative.

Drupal core deprecated assertion methods in PHPUnit test classes. A handful of modules decided to replace the method under the same name. PHPStan would find the method, detect the original method was deprecated, and report errors on that method's usage. There was no way to say: "Wait, trust me, this isn't deprecated. I know what I'm doing!" The only approach was to use an inline comment or add the error message to the ignored error setting.

If you scan the Address module, you'll get an error like the following:

Call to deprecated method assertOptionSelected() of class Drupal\Tests\address\FunctionalJavascript\AddressDefaultWidgetTest. 
Deprecated in drupal:8.2.0 and is removed from drupal:10.0.0. 
Use $this->assertSession()->optionExists() instead and check the "selected" attribute yourself.

It would be cumbersome to go through and annotate all of the calls for this with a preceding @phpstan-ignore-next-line

$this->assertSession()->fieldValueEquals($field_name . '[0][address][locality]', $address['locality']);
// @phpstan-ignore-next-line
$this->assertOptionSelected($field_name . '[0][address][administrative_area]', $address['administrative_area']);
$this->assertSession()->fieldValueEquals($field_name . '[0][address][postal_code]', $address['postal_code']);
// @phpstan-ignore-next-line
$this->assertOptionSelected($field_name . '[0][address][country_code]', $country_code);

I have opened a merge request for the Address module to add this annotation.

--- a/tests/src/FunctionalJavascript/AddressDefaultWidgetTest.php
+++ b/tests/src/FunctionalJavascript/AddressDefaultWidgetTest.php
@@ -660,6 +660,8 @@ class AddressDefaultWidgetTest extends WebDriverTestBase {
    *   messages: use \Drupal\Component\Utility\SafeMarkup::format() to embed
    *   variables in the message text, not t(). If left blank, a default message
    *   will be displayed.
+   *
+   * @not-deprecated
   protected function assertOptionSelected($id, $option, $message = '') {
     $elements = $this->xpath('//select[@name=:id]//option[@value=:option]', [':id' => $id, ':option' => $option]);

I don't know if Drupal will have another round of deprecated helper methods like this again, but it will be easier to avoid false-positive deprecation warnings!