Skip to content

Incorrect behavior of FirstClassCallableRector with private methods #8659

@bradjones1

Description

@bradjones1

Bug Report

Subject Details
Rector version last dev-main
Installed as composer dependency

Minimal PHP Code Causing Issue

I have a logging handler that my framework generally configures to use some other handler to process exceptions, but I need to instantiate my own instance and force it to use its own exception handler. This is in a private method.

Rector wants to change this to a first-class callable, but that doesn't work because it's bound to the current scope. This should be a skip.

See https://getrector.com/demo/97e13a54-fd5d-4cab-9dfa-7b3f8ea8cfce

<?php

class WithPrivateMethod {
  /** @var callable */
  protected $handler;

  public function setHandler(?callable $handler): void {
    $this->handler = $handler;
  }

  public function doTheThing(): void {
    ($this->handler)();
  }

  private function defaultHandler(): void {
    echo 'default handler';
  }
}

final class DemoFile
{
  public function run(bool $param)
  {
    $thing = new WithPrivateMethod();
    $thing->setHandler([$thing, 'defaultHandler']);
    $thing->doTheThing();
  }
}

Interestingly, if you do not instantiate the class in question in the local scope where the change is made, Rector does the "right thing" and skips it. See: https://getrector.com/demo/3548d616-a70d-4e2a-9119-59758d5d4ab9

Responsible rules

  • FirstClassCallableRector

Expected Behavior

Skip.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions