Skip to content

Squiz.Scope.StaticThisUsage false positive for Closure::bind closure inside static method #1357

Closed

Description

@janedbal

Describe the bug

Squiz.Scope.StaticThisUsage reports $this used inside a closure defined within a static method, even when that closure is explicitly bound to an object via Closure::bind() before being invoked.

At runtime, $this in the closure refers to the bound object ($newThis), so no runtime error occurs. The sniff appears to treat $this inside the nested closure as if it was used in the static method scope.

Code sample

  <?php declare(strict_types=1);

  final class Target
  {
      public $x = 2;
  }

  final class Repro
  {
      public static function run(): void
      {
          $target = new Target();

          \Closure::bind(
              function (): void {
                  $this->x = 1; // Usage of "$this" in static methods will cause runtime errors 
              },
              $target,
              Target::class,
          )();
      }
  }

Custom ruleset

  <?xml version="1.0"?>
  <ruleset name="Repro">
    <rule ref="Squiz.Scope.StaticThisUsage"/>
  </ruleset>

To reproduce

  1. Create test.php with the code sample above
  2. Create ruleset.xml with the custom ruleset above
  3. Run phpcs -s --standard=ruleset.xml test.php
  4. See error message displayed
  ----------------------------------------------------------------------
  FOUND 1 ERROR AFFECTING 1 LINE
  ----------------------------------------------------------------------
   16 | ERROR | Usage of "$this" in static methods will cause runtime errors (Squiz.Scope.StaticThisUsage.Found)
  ----------------------------------------------------------------------

Expected behavior

No error

Versions

Operating System Ubuntu 24.04.3 LTS
PHP version 8.4.15
PHP_CodeSniffer version 4.0.1
Standard Squiz
Install type Composer (local dev dependency)

Please confirm

  • I have searched the issue list and am not opening a duplicate issue.
  • I have read the Contribution Guidelines and this is not a support question.
  • I confirm that this bug is a bug in PHP_CodeSniffer and not in one of the external standards.
  • I have verified the issue still exists in the 4.x branch of PHP_CodeSniffer.

Activity

  1. added this to the 4.0.2 milestone on Mar 1, 2026
  2. jrfnl commented on Mar 1, 2026

    @jrfnl
    Member

    @janedbal Thank you for reporting this issue. I can confirm this issue as reproducible.

    The sniff has previously had multiple changes regarding this behaviour and it looks like these were incomplete/contradicted each other in part.
    For reference;

    The sniff currently:

    • Examines T_FUNCTION tokens when in an OO scope, including methods in anonymous classes.
    • Skips over nested anonymous classes found within the body of an OO method.

    I believe the following two changes are needed:

    1. Skip over nested anonymous functions with a closed scope (i.e. skip over T_CLOSURE, not T_FN) when examining the body of OO methods.
      👆🏻 This would solve the issue as reported here.
    2. Examine the body of static closures for the use of $this (but ignore non-static closures) and do this independently of the scope within which the closure is defined.

    I've opened PR #1377 to address this. Testing and/or review of the PR would be appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions