A condensed overview of Tyhpdef syntax — the declaration-only language for describing existing PHP code to the Tyhp compiler. Similar to TypeScript's .d.ts files. For full details, follow the link below each feature.
Every .tyhpdef file starts with the <?tyhpdef tag. Supports namespaces (semicolon and braced styles) and use/import statements. Only declarations are allowed — no function bodies or executable code.
<?tyhpdef
const string APP_NAME;
function myPhpFunction(string $input): int;
Declare global PHP variables and constants with types. Use as for aliasing. Top-level deprecated/obsolete work. Tyhpdef ?? records PHP's expected start value (the live value may differ); & is not a tyhpdef form.
bool $debugMode;
string $legacy_app_name as $appName;
const string APP_ENV;
const int \MAX_LOOPS_ALLOWED as MAX_LOOPS;
Declare function signatures with typed parameters (including optional, reference, and variadic), generic type parameters, async functions, function aliases, and extension functions. fallback function is a signature PHP defines only when that name is still empty; Composer autoload.files order chooses among packages. declare(ext="name") / declare(ext="!name") keeps a block when that extension's tyhpdef package is loaded or absent. Overlay partial function (optionally as) merges attributes or renames without restating the signature. Version-specific signatures use #[\Tyhp\Php("…")] or declare(php=…) in .tyhpdef.
function \array_map<T, U>(callable(T): U $callback, array<T> $array): array<U>;
async function fetchUserData(int $userId): UserData;
function \array_key_exists as keyExists(int|string $key, array $array): bool;
function toCamelCase(extends string $str): string;
#[\Tyhp\Php(">=8.2 <8.4")]
function example(string $v): mixed;
#[\Tyhp\Php(">=8.4")]
function example(string $v, bool $strict = false): string;
Attach Tyhp extension methods and operator overloads to PHP types. Standalone extension Name extends Type { } (or nested extends Type { } groups, with no header target) uses short fn / operator + => members; $this is the block target; return types required; empty {} is an error. Class-body extension fn / extension operator are thin mappings (=> only, fully erased; PHP cannot call them; $this / self are the enclosing class). File-level use extension is opt-in unless global use extension. tyhp/core globally imports \Tyhp\StringExtensions and the other scalar catalogs. use extension on a tyhpdef class auto-activates that type’s attached surface. Bodyless operator …; is native PHP passthrough; bodyless extension operator is an error. hide / operator insteadof are allowed; as on operators is an error. #[\Tyhp\Php] is illegal on extension { } (TYHP4304); wrap with declare(php=…). Multi-statement bodies live in tyhp_src/ with class PhpName as Name__tyhpExtensionBacker.
extension StringOperators extends string {
fn toUpper(): string
=> StringOperators__tyhpExtensionBacker::toUpper($this);
operator * (self $left, int $right): string
=> StringOperators__tyhpExtensionBacker::__multiply($left, $right);
}
class Money {
public function plus(Money $other): Money;
extension operator +(self $left, self $right): self => $left->plus($right);
extension fn formatCurrency(string $locale = "en_US"): string
=> $locale . " " . $this->__toString();
use extension MoneyFormatting {
MoneyFormatting::format as formatExtended;
};
}
Declare PHP interfaces with fully typed method signatures, constants, inheritance (extends), generic type parameters with constraints, method overloads, and async methods.
interface Repository<T> {
public function find(int $id): ?T;
public function save(T $entity): void;
}
interface Stream extends Readable, Writable {
public function close(): void;
}
Declare PHP classes with properties (including optional ?? expected start values and bodyless hooked { get; set; } / { &get; }), methods, constructors (with parameter promotion — property ??, parameter =), constants (?? only, not =), extends/implements, generics, trait usage, native operator members, class aliasing with as, and base/include partial (additive members; duplicate = error; missing target = error; omit is overlay-only). A reserved-word short name (is, isset, …) is written fully qualified (class \Hamcrest\Core\Is). Overlay last-wins brace partial, header-only partial class Foo<T>;, partial function, and omit are documented in Tyhpdef Overlays.
class Collection<T> {
public function add(T $item): void;
public function map<U>(callable(T): U $transform): Collection<U>;
}
class Holder {
public string $name { get; set; }
public array $items { &get; set; }
}
class \Vendor\LongNamespace\SomeClass as ShortName {
public function doWork(): void;
}
extra.tyhp.package "include" on composer.json is the baseline (duplicates error). "overlay" loads after, stubs then hand, last Tyhp name wins. Overlay brace partial replaces listed members (missing target = warning). Overlay partial class Foo<T> implements …; (also interface / trait / enum) replaces written header clauses and keeps unlisted members. Overlay partial function merges attributes onto an existing callable without restating the signature. partial function X as Y; and partial class X as Y; rename the current Tyhp name unless the same overlay file also keeps X. Match later overlays to the live Tyhp name. omit hides a symbol (overlay-only). // @overlay-against: stamps the Layer 1 signature. tyhp overlay create / stamp. tyhp symbol_tree dumps the bound names.
<?tyhpdef
// @overlay-against: interface Iterator extends Traversable
partial interface Iterator<TKey = mixed, TValue = mixed> extends \Traversable<TKey, TValue>;
partial interface Iterator {
public function current(): TValue;
}
omit function \array_map();
#[\Tyhp\Optimize\Pure]
partial function \str_contains;
partial function \strtolower as str2LC;
partial function \strtoupper;
partial function \strtoupper as str2UC;
partial class SplObjectStorage;
partial class SplObjectStorage as ObjectStorage;
Name-only placeholders for types, functions, or constants this package mentions but does not own (suggest / require-dev Composer peers, optional extensions, author-only tyhpdefs). Legal in tyhpdef signatures; not usable in .tyhp (TYHP4307). A real declaration of the same name silently replaces the placeholder. Use extern \Name; when the kind is unknown. When the kind is known, write the same kind as the originating declaration (extern interface for an interface); a mismatch is TYHP8029. tyhp build writes author-only owners into package.tyhpdef; --package-path / --source write _tyhpdef/externs.tyhpdef.
<?tyhpdef
extern \Elastica\Client;
// @provided-by: tyhpdef/php-ext-curl
extern class \CurlHandle;
extern interface \Psr\Log\LoggerInterface;
extern function \bcadd;
extern const \GMP_ROUND_PLUSINF;
Declare unit enums (no backing value) and backed enums (string or int). Supports case values, methods, interface implementation, constants, aliasing, and deprecated cases. Every enum is \UnitEnum (and \BackedEnum when backed) without listing those interfaces; harvested stubs may keep them. Do not redeclare cases / from / tryFrom.
enum HttpMethod: string {
case GET = "GET";
case POST = "POST";
case PUT = "PUT";
}
enum Permission: int implements \Stringable {
case Read = 1;
case Write = 2;
public function __toString(): string;
}
Declare PHP traits with typed properties, methods, constants, abstract methods, and generic type parameters. Generic traits specify concrete type arguments when used in Tyhp code.
trait Collection<T> {
public function add(T $item): void;
public function getItems(): array<T>;
}
// in Tyhp code:
use Collection<User>;
Value types backed by PHP associative arrays. Named as type Name = struct { … };. Support required and optional properties, property aliases for non-identifier array keys, defaults, inheritance, nesting, generics, and inline struct { … } in type position.
type UserProfile = struct {
string $name;
?string $bio;
string $role = "user";
};
type ApiResponse<T> = struct {
bool $success;
?T $data;
?string 'Reply-To' as $replyTo;
};
Create named aliases for complex type expressions using the type keyword. Supports generic parameters with constraints. Allowed at root level or inside namespace blocks. Tyhpdef aliases are type-only: they do not emit a PHP factory; typeof inlines the body.
type Scalar = int|float|string|bool;
type StatusCode = 200|301|302|404|500;
type Result<T, TError extends \Throwable> = T|TError;
type Predicate<T> = callable(T): bool;
Both braced and semicolon-style namespace declarations. Multiple namespaces per file allowed. PHP items can be imported into a different tyhpdef namespace using leading-backslash fully-qualified names.
namespace App\Models {
class User { public int $id; public string $name; }
}
namespace EL {
class \EmailerLib\Emailer {
public function __construct(string $subjectLine): void;
}
}
Alias nearly anything with as — functions, classes, interfaces, traits, enums, properties, methods, constants, variables, and enum cases. Only the aliased name is available in Tyhp.
class LegacyApi as Api {
public string $usr_nm as $username;
public function get_usr as getUser(int $id): ?User;
}
Declare multiple signatures for the same function/method name to describe PHP functions with varying parameter types and return types. Supports static value type overloads, generic overloads, and async overloads.
function \json_decode(string $json, true $assoc): JsonAssoc|null;
function \json_decode(string $json, false $assoc): JsonObject|null;
function \json_decode(string $json, null $assoc = null): JsonObject|null;
public function find(int $id): ?User;
public function find(string $uuid): ?User;
public function find(array<string, mixed> $criteria): array<User>;
deprecated and obsolete Keywordsdeprecated produces a compiler warning but still compiles. obsolete produces a compiler error and blocks compilation. Both must appear before all other modifiers. In this alpha they are enforced on top-level functions, classes, interfaces, traits, enums, constants, and variables — not on class/interface members or enum cases.
deprecated function \mysql_connect(string $server, string $user, string $pass): \mysqli|false;
obsolete function \md5(string $string, bool $binary = false): string;
When tyhpdef declarations don't match actual PHP code, runtime errors can occur. Declare exception hierarchies and document throws with @throws (documentation only in this alpha).
class \InvalidArgumentException extends \LogicException {
public function __construct(
string $message = "",
int $code = 0,
?\Throwable $previous = null
): void;
}
/** @throws \JsonException When JSON encoding fails */
function \json_encode(mixed $value, int $flags = 0, int $depth = 512): string|false;