Tip
DO mark helper classes, optional-extension backends, and shared constants internal when they exist only so this package can compile. They stay in the emitted PHP and stay usable inside the same tyhp.json.
Tier 2Complete
internal is a Tyhp visibility keyword. Mark implementation details that belong in this project but must not appear in the published package.tyhpdef. Consumers of the compiled library type-check against that file, so they never see those symbols.
internal has no PHP equivalent. The compiler strips it on emit: class members become public; top-level classes, functions, and constants are unprefixed (PHP’s default). Same-project .tyhp can still use the symbols.
Apply internal to a top-level class, interface, trait, enum, function, constant, type alias, or extension, and to members (methods, properties, constants, enum cases).
<?tyhp
internal class GmpBackend {
public function add(string $a, string $b): string {
return \gmp_strval(\gmp_add($a, $b));
}
}
internal function formatScale(int $scale): string {
return (string)$scale;
}
internal const BACKEND_ID = 1;
public class Decimal {
public function add(Decimal $other): Decimal {
return $this->addWith(new GmpBackend(), $other);
}
internal function addWith(GmpBackend $backend, Decimal $other): Decimal {
// ...
}
}
Do not combine internal with public, protected, or private on the same declaration (TYHP4002). internal static, internal readonly, internal abstract, and internal final are allowed.
tyhp build for a library always writes package.tyhpdef. Symbols marked internal are omitted, the same way private members are omitted. A public type’s internal members are left out of that file.
<?tyhpdef
class Decimal {
public function add(Decimal $other): Decimal;
}
GmpBackend, formatScale, BACKEND_ID, and Decimal::addWith do not appear. Consumers cannot name them through the published tyhpdef.
Use internal for backends, helpers, and other author-only code that must compile in this package but must not become part of the consumer API. Put author-only tyhpdef packages in require-dev and leave them out of extra.tyhp.require — see Composer Runtime Packages.
<?php
class GmpBackend {
public function add(string $a, string $b): string {
return \gmp_strval(\gmp_add($a, $b));
}
}
function formatScale(int $scale): string {
return (string)$scale;
}
const BACKEND_ID = 1;
class Decimal {
public function add(Decimal $other): Decimal {
return $this->addWith(new GmpBackend(), $other);
}
public function addWith(GmpBackend $backend, Decimal $other): Decimal {
// ...
}
}
PHP does not enforce the project boundary. The published tyhpdef is what hides the names from Tyhp consumers.
DO mark helper classes, optional-extension backends, and shared constants internal when they exist only so this package can compile. They stay in the emitted PHP and stay usable inside the same tyhp.json.
DON'T combine internal with public, protected, or private. That is TYHP4002. Write internal function helper(): void (project-scoped) or private function helper(): void (class-scoped), not both.
package.tyhpdef omitTYHP4002