You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* reorganize documentation sections
* Refactor GenericValidator to handle invalid class syntax gracefully and improve test cases for unsupported type syntax
* Add support for new types: uppercase-string, non-empty-uppercase-string, and array-key; update validators and tests accordingly
* Add int-mask type checking support
* Added runtime checking for offset array access
* Add support for offset access types and integer bitmasks in documentation
* fix name argument parsing mismatch cuasing false positive type-errors and document it.
TypePHP is the first pure-PHP library that transparently enforces extended PHPDoc type contracts (generics, array shapes, scalar refinements, and callables) at runtime during execution, without introducing any new syntax or requiring C-extensions.
19
+
TypePHP is a transparent, pure-PHP runtime type checker. You don't have to refactor a single line of your codebase, setup complex build toolchains, or compile C-extensions and simply run your existing code, and TypePHP will enforce your extended PHPDoc contracts (generics, array shapes, `key-of`/`value-of` extractions, and scalar refinements) dynamically at runtime.
15
20
16
21
17
22
**[Read the full TypePHP documentation »](https://typephp-php.github.io/typephp/)**
## Parameter Renaming ($id → $userId) & Position Shifts
296
296
297
-
PHP permits child classes to rename parameters when implementing an interface or extending a class. TypePHP maps inherited parameter contracts by **index position** (0, 1, 2...) rather than parameter name:
297
+
When a child class or attribute constructor overrides a parent method, parameter positions or parameter names may shift. TypePHP resolves parameter contract inheritance using **Name-First Resolution**:
298
+
299
+
1.**Name Matching:** If a parameter name in the child method matches a parameter name in the parent class (e.g. `$api`), the parent's contract is inherited by that parameter regardless of its position index in the child.
300
+
2.**Position Fallback:** If a parameter is renamed in the child class (e.g., `$id` $\rightarrow$ `$userId`), TypePHP falls back to matching by position index.
298
301
299
302
```php
300
-
interface UserApiInterface
303
+
class BaseField
301
304
{
302
305
/**
303
-
* Interface uses parameter name $id
306
+
* Parent constructor has $api at position #1
304
307
*
305
-
* @param positive-int $id
308
+
* @param string $type
309
+
* @param bool|array{admin-api: bool} $api
306
310
*/
307
-
public function find(int $id): bool;
311
+
public function __construct(string $type, bool|array $api = false) {}
308
312
}
309
313
310
-
class UserApi implements UserApiInterface
314
+
class OneToManyRelation extends BaseField
311
315
{
312
-
// Child renames parameter $id to $userId
313
-
public function find(int $userId): bool
314
-
{
315
-
return true;
316
+
/**
317
+
* Child inserts $entity, $ref, $onDelete BEFORE $api (position shift!)
> **Execution Order Note:** Native PHP type hints (e.g., `int $id`, `string $username`) are evaluated by PHP's C-engine *before* function execution begins. TypePHP's extended PHPDoc contracts (e.g., `positive-int`, `non-empty-string`) execute at the very start of the function/method body. If a native type hint fails, PHP throws its native `TypeError` before TypePHP's guard rails run.
37
37
38
+
---
39
+
## PHP 8.0+ Named Arguments
40
+
41
+
TypePHP natively supports PHP 8.0+ Named Arguments. Because parameter contracts are mapped by parameter name rather than argument position index, you can pass named arguments in any order, and TypePHP will accurately validate each parameter:
42
+
43
+
```php
44
+
<?php
45
+
46
+
declare(strict_types=1);
47
+
48
+
/**
49
+
* @param positive-int $id
50
+
* @param non-empty-string $username
51
+
* @param int<1,100> $age
52
+
*/
53
+
function registerUser(int $id, string $username, int $age): void
54
+
{
55
+
// ...
56
+
}
57
+
58
+
// Valid Call: Arguments passed in completely reversed/swapped order
59
+
registerUser(age: 25, username: 'Alice', id: 42);
60
+
61
+
// Invalid Call: $id (-5) passed as 3rd named argument
62
+
registerUser(age: 25, username: 'Alice', id: -5);
63
+
// Throws: TypeError: registerUser(): Argument $id must be of type positive-int, negative int (-5) given
Copy file name to clipboardExpand all lines: docs/index.md
+75-55Lines changed: 75 additions & 55 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@ layout: home
4
4
hero:
5
5
name: "TypePHP"
6
6
text: "Transparent Runtime Type Enforcement"
7
-
tagline: "The first pure PHP library to enforce DocBlock types at runtime transparently without introducing any new syntax. Validates generics, array shapes, and advanced type contracts during execution."
7
+
tagline: "No transpilation. No build steps. No C-extensions. Just 100% pure PHP that makes your existing DocBlocks scream the moment types fail."
8
8
actions:
9
9
- theme: brand
10
10
text: "Get Started →"
@@ -16,17 +16,52 @@ hero:
16
16
features:
17
17
- title: "Zero Production Overhead"
18
18
details: "Install as a development dependency to enforce strict types during local testing and CI/CD pipelines, guaranteeing absolute zero performance cost in live production environments."
19
+
- title: "No Transpilation or C-Extensions"
20
+
details: "Operates 100% in pure PHP user-land using native stream wrappers and AST transformations. No build scripts, Node.js tools, or C-extensions required."
19
21
- title: "True Runtime Generics"
20
22
details: "Binds generic template types to specific object instances dynamically using native WeakMap memory tracking."
21
-
- title: "Typed Arrays & Shapes"
22
-
details: "Deeply validates sequential lists, typed class arrays, and strict associative array shape structures right out of the box."
23
-
- title: "PHP 8.4 Support"
24
-
details: "Native support for intercepting and validating PHP 8.4 Property Hooks (get/set) and Asymmetric Visibility (public private(set))."
23
+
- title: "Arrays, Shapes & Extractions"
24
+
details: "Deeply validates sequential lists, typed arrays, array shapes, and key-of / value-of constant extractions out of the box."
25
25
---
26
26
27
+
::: tip Pure PHP • Zero Transpilation • Zero Build Steps
28
+
**You don't have to change a single line of code, and you don't need a compilation build toolchain.** TypePHP operates entirely in native PHP user-land and no custom PHP binaries, C-extensions, or Node.js transpilers needed. Drop TypePHP into your existing project, run your code, and your DocBlocks will instantly start screaming at runtime when dynamic data violates a type contract.
29
+
:::
30
+
27
31
## See It In Action
28
32
29
-
TypePHP is the first pure PHP library that operates entirely in user-land using native stream wrappers and AST transformations. Because it requires no C-extensions or FFI, you can drop it into any PHP 8.1+ project effortlessly. It parses your standard PHPDoc annotations and enforces them the moment your code runs.
33
+
TypePHP operates entirely in user-land using native stream wrappers and AST transformations. Because it requires no C-extensions or FFI, you can drop it into any PHP 8.1+ project or web framework effortlessly. It reads your existing PHPDoc annotations and enforces them the moment your code runs.
// Throws TypeError: Argument $params['driver'] must be a key of DriverManager::DRIVER_MAP
94
122
```
95
123
96
124
---
97
125
98
-
## Precise Stack Trace & Error Reporting
126
+
## Precise Call-Site Trace Attribution
99
127
100
-
TypePHP injects single-line guard rails without shifting your source file line numbers.
128
+
A common problem with AST code injection is that adding new statements pushes subsequent code down, causing line numbers in stack traces to drift out of sync.
101
129
102
-
When an inline variable or type contract fails, framework error handlers and test runners (like Pest, PHPUnit, and Whoops) point **directly to the exact line number** where the invalid assignment or argument occurred in your application code:
130
+
TypePHP solves this with **Zero Line-Drift Formatting**. Injected guard rails are squashed onto single lines and appended directly to existing code blocks. **Line numbers in your source files remain 100% identical before and after transformation.**
103
131
104
-
```
105
-
FAILED Tests\SomeTest > test
106
-
107
-
TypeError: Variable $typeArray[3] must be of type int, string '1' given
108
-
109
-
at tests/SomeTest.php:7
110
-
3| declare(strict_types=1);
111
-
4|
112
-
5| test('test', function () {
113
-
6| /** @var array<int> */
114
-
➜ 7| $typeArray = [1, 2, 3, '1'];
115
-
8|
116
-
9| expect($typeArray)->toBeArray();
117
-
10| });
118
-
```
132
+
When a type contract fails, web exception handlers (**Laravel Ignition, Whoops, Symfony ErrorHandler**) and CLI test runners (**Pest, PHPUnit**) point **directly to the exact line number** where the invalid assignment or return value occurred in your application code:
0 commit comments