logoalt Hacker News

eithed • today at 1:38 PM • 1 reply • view on HN

Natively: no. Via tools like phpstan and psalm: yes, per OP. Link to relevant docs: https://psalm.dev/docs/annotating_code/templated_annotations... or https://phpstan.org/blog/generics-by-examples

One can declare:

  final class Door {}

  /**
   * @template T
   */
  final class Box
  {
      /** @param T $value */
      public function __construct(private mixed $value) {}

      /** @return T */
      public function get(): mixed
      {
          return $this->value;
      }
  }

  final class DoorInspector
  {
      /** @param Box<Door> $box */
      public function __construct(private Box $box) {}

      public function inspect(): void
      {
          $this->box->get()->open(); // analyser knows this is a Door
      }
  }

  new DoorInspector(new Box(new Door()));   // OK
  new DoorInspector(new Box('not a door')); // error: Box<string> given
You can even bind a template by a generic type with "of":

  final class Door {}

  /**
   * @template T
   */
  class Box
  {
      /** @param T $value */
      public function __construct(private mixed $value) {}

      /** @return T */
      public function get(): mixed
      {
          return $this->value;
      }
  }

  /** @extends Box<Door> */
  final class DoorBox extends Box {}

  /**
   * @template T
   * @template F of Box<T>
   */
  final class Shelf
  {
      /** @param F $box */
      public function __construct(private Box $box) {}

      /** @return F */
      public function box(): Box
      {
          return $this->box;
      }

      /** @return T */
      public function item(): mixed
      {
          return $this->box->get();
      }
  }

  $shelf = new Shelf(new DoorBox(new Door()));
  $shelf->box();  // DoorBox
  $shelf->item(); // Door

Replies

someothherguyy • today at 3:50 PM

yeah, it is a real pain in the ass. imagine if php 8 accepted the RFC for generics