Tip
DO: Include failure return types (false, null) in your tyhpdef function declarations even when they make the type more complex. Accurate types prevent unhandled runtime failures.
Tier 0 · Story 02Complete
While Tyhp performs extensive compile-time type checking, tyhpdef declarations describe external PHP code that the compiler cannot verify at compile time. If a tyhpdef declaration does not accurately reflect the actual PHP implementation, runtime errors can occur. This page covers how to declare exception classes, document throwable functions, and understand the runtime implications of tyhpdef mismatches.
Exception and error classes from PHP libraries can be declared in tyhpdef just like any other class. Declaring them provides the compiler with the exception hierarchy for type checking in catch blocks.
<?tyhpdef
class \InvalidArgumentException extends \LogicException {
public function __construct(
string $message = "",
int $code = 0,
?\Throwable $previous = null
): void;
public function getMessage(): string;
public function getCode(): int;
public function getFile(): string;
public function getLine(): int;
public function getTrace(): array;
public function getPrevious(): ?\Throwable;
public function getTraceAsString(): string;
}
class \RuntimeException extends \Exception {
public function __construct(
string $message = "",
int $code = 0,
?\Throwable $previous = null
): void;
}
When a PHP library defines its own exception classes, declare them with their full inheritance chain so the compiler can validate catch blocks and exception type narrowing.
<?tyhpdef
namespace Guzzle\Exception {
interface GuzzleException extends \Throwable {}
class TransferException extends \RuntimeException implements GuzzleException {
public function __construct(
string $message = "",
int $code = 0,
?\Throwable $previous = null
): void;
}
class RequestException extends TransferException {
public function getRequest(): \Psr\Http\Message\RequestInterface;
public function getResponse(): ?\Psr\Http\Message\ResponseInterface;
public function hasResponse(): bool;
}
class ConnectException extends TransferException {
public function getRequest(): \Psr\Http\Message\RequestInterface;
}
class ClientException extends RequestException {}
class ServerException extends RequestException {}
}
Use the @throws doc comment annotation on function and method declarations to document which exceptions a function can throw. Tyhp records these annotations for humans and for future tooling. This alpha does not require callers to catch or declare them — there is no checked-exception / throws-effect analysis yet.
<?tyhpdef
/**
* @throws \JsonException When JSON encoding fails with JSON_THROW_ON_ERROR
*/
function \json_encode(
mixed $value,
int $flags = 0,
int $depth = 512
): string|false;
/**
* @throws \InvalidArgumentException When the date format is invalid
* @throws \RuntimeException When timezone data is unavailable
*/
function \date_create_from_format(
string $format,
string $datetime,
?\DateTimeZone $timezone = null
): \DateTime|false;
class DatabaseConnection {
/**
* @throws \PDOException When the connection fails
*/
public function __construct(
string $dsn,
?string $username = null,
?string $password = null,
?array $options = null
): void;
/**
* @throws \PDOException When the query is invalid
*/
public function query(string $sql): \PDOStatement;
}
Tyhpdef global imports are type information only. This alpha does not emit runtime ErrorException checks or apply tyhpdef ?? defaults. Handle missing PHP globals at the use site.
If a tyhpdef declaration says a class has certain methods, properties, or constants that the actual PHP class does not have, you may get runtime errors when the code attempts to access them. The compiler trusts tyhpdef declarations at compile time, so mismatches are only caught at runtime.
<?php
class User {
public string $name;
// Missing: public function getEmail(): string
}
<?tyhpdef
class User {
public string $name;
public function getEmail(): string;
}
In this example, Tyhp code calling $user->getEmail() will compile without errors because the tyhpdef says the method exists. At runtime, PHP will throw: Fatal error: Call to undefined method User::getEmail().
If a tyhpdef declares a function's return type differently from what the PHP function actually returns, the Tyhp compiler will accept the tyhpdef's type at compile time, but runtime behavior may differ.
<?tyhpdef
// Declared as always returning string, but the actual PHP function
// can return false on failure
function \file_get_contents(string $filename): string;
If the tyhpdef omits the false return type, the compiler will not require null/false checks at call sites, potentially leading to unhandled runtime failures.
generate_tyhpdef is not shipped)tyhp lint so tyhpdef files parse and bindisset, ?? in code, nullable types)DO: Include failure return types (false, null) in your tyhpdef function declarations even when they make the type more complex. Accurate types prevent unhandled runtime failures.
DO: Declare the full exception class hierarchy for libraries you depend on. This allows the compiler to validate catch block type narrowing and prevents catching overly broad exception types.
DON'T: Narrow return types in tyhpdef to be more specific than the actual PHP function. If a PHP function returns string|false, do not declare it as returning just string — this hides potential runtime failures.
DON'T: Declare methods or properties in tyhpdef that do not exist on the actual PHP class. The compiler will trust your declarations, and runtime errors will result when the missing members are accessed.
@throws doc comment annotations to document which exceptions functions and methods can throw (documentation only in this alpha — the compiler does not enforce that callers handle them)?? is not applied in this alphafalse, null)generate_tyhpdef is Story 20 and is not shipped)