Skip to content

Latest commit

 

History

History
85 lines (66 loc) · 2.45 KB

File metadata and controls

85 lines (66 loc) · 2.45 KB

Classes and interfaces

Generic classes, interfaces, and traits declare type parameters in angle brackets after the name. Each unique instantiation produces its own real class at compile time.

Example

<?php
declare(strict_types=1);

namespace App;

class Box<T> {
    public function __construct(public T $item) {}
    public function get(): T { return $this->item; }
}

interface Container<T> {
    public function add(T $item): void;
    public function all(): array;
}

trait HasItem<T> {
    public T $item;
}

$intBox = new Box::<int>(42);
$strBox = new Box::<string>('hello');

What gets emitted

The template Box<T> produces an empty marker interface at the original FQN, plus one specialized class per concrete arg:

// dist/App/Box.php (marker)
namespace App;
interface Box {}

// cache/Generated/App/Box/T_<hash-of-int>.php
namespace XPHP\Generated\App\Box;
class T_3a9f... implements \App\Box {
    public function __construct(public int $item) {}
    public function get(): int { return $this->item; }
}

The new Box::<int>(42) call site rewrites to new \XPHP\Generated\App\Box\T_3a9f...(42). From the user's perspective the syntax is new Box::<int>(42); the long FQN is an implementation detail.

Rules

  • Type parameters are simple identifiers (T, K, V, TElement). No leading $.
  • Any arity works: Box<T>, Map<K, V>, Triple<A, B, C>.
  • Type parameters can appear anywhere a type can — properties, method params, return types, new expressions, type hints.
  • Nesting works at arbitrary depth: Box<List<T>>, Map<K, List<V>>.
  • Anonymous classes can't be generic — new class<T> { ... } is a syntax error.

Caveats

  • Marker-interface instanceof$x instanceof App\Box returns true for every Box<...> specialization. This is an intentional convenience; see runtime semantics.
  • Traits don't get markersinstanceof SomeTrait doesn't work in PHP, so generic traits are dropped from the emit after specialization.
  • Variance edges — when +T or -T is declared, specializations get real extends chains. See variance.

See also

  • Test fixture: test/fixture/compile/box_generic/
  • Test fixture: test/fixture/compile/generic_interface/
  • Test fixture: test/fixture/compile/nested_instantiation/
  • Related: methods and functions, turbofish