Lucas Bustamante
Lucas Bustamante

Reputation: 17256

How do I type-hint __call() magic method in PHP?

I am implementing an Adapter pattern for testing purposes, and I would like to type hint the return of the Adapter with the methods of two distinct classes, how can I achieve that?

class Foo {
  public function somethingOnlyFooHave() {};
}

class Adapter {
  protected $handler;

  public function __construct(object $handler) {
    $this->handler = $handler;
  }

  public function __call($name, ...$args) {
    $this->handler->$name($args);
  }

  public function somethingOnlyTheAdapterHave() {}
}

$foo = new Adapter(new Foo);

// How can I get type-hinting for both the Adapter and Foo?
$foo->somethingOnlyFooHave();
$foo->somethingOnlyTheAdapterHave();

Upvotes: 0

Views: 981

Answers (2)

Oddman
Oddman

Reputation: 3959

Honestly this is why the adapter pattern is generally seen as an anti-pattern, whereas strategy is the one that is preferred - adapters can get you in all sorts of problems :)

As stated above, however - with recent versions of PHP you can now use union types, and typehint both class return values. It is much better however, from a code stability perspective, to instead have each of your adapters implement an interface, and typehint that interface.

Upvotes: 0

Lucas Bustamante
Lucas Bustamante

Reputation: 17256

Seems PHP can't do this natively, but If you're using PHPStorm 2018.3+, you can use Union Types (or Intersection Types), as long as it's not on the __construct:

class Foo {
    public function somethingOnlyFooHave() {}
}

class Adapter {
    protected $handler;

    public function __construct(object $handler) {
        $this->handler = $handler;
    }

    public function __call($name, ...$args) {
        $this->handler->$name($args);
    }

    /**
     * @return Adapter|Foo
     */
    public function get() {
        return $this;
    }

    public function somethingOnlyAdapterHave() {}
}

$foo_adapter = ( new Adapter(new Foo) )->get();

// The following methods receives type-hinting:
$foo_adapter->somethingOnlyFooHave();
$foo_adapter->somethingOnlyAdapterHave();

Useful links:

Upvotes: 0

Related Questions