|
18 | 18 |
|
19 | 19 | TypePHP is a transparent, pure-PHP runtime type checker. You don't have to refactor a single line of your codebase, set up complex build toolchains, or compile C-extensions. 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. |
20 | 20 |
|
21 | | - |
22 | 21 | **[Read the full TypePHP documentation »](https://typephp-php.github.io/typephp/)** |
23 | 22 |
|
24 | 23 | **[Quick Start Guide »](https://typephp-php.github.io/typephp/getting-started/quick-start)** |
25 | 24 |
|
| 25 | +--- |
| 26 | + |
| 27 | +## Live Diagnostics (Zero Line-Drift) |
| 28 | + |
| 29 | +When a type contract fails, web exception handlers (**Laravel Ignition, Symfony ErrorHandler, Whoops**) and CLI test runners (**Pest, PHPUnit**) highlight **the exact line of code** in your application where the invalid data was passed, with **zero line-drift**: |
| 30 | + |
| 31 | +### Web Framework Trace (Laravel Ignition) |
| 32 | +<p align="center"> |
| 33 | + <img src="docs/public/laravel-error-screen.png" alt="Laravel Ignition Exception Trace" width="100%"> |
| 34 | +</p> |
| 35 | + |
| 36 | +### Web Framework Trace (Symfony ErrorHandler) |
| 37 | +<p align="center"> |
| 38 | + <img src="docs/public/symfony-error-screen.png" alt="Symfony ErrorHandler Exception Trace" width="100%"> |
| 39 | +</p> |
| 40 | + |
| 41 | +### CLI Test Runner Trace (Pest PHP) |
| 42 | +<p align="center"> |
| 43 | + <img src="docs/public/pest-error-screen.png" alt="Pest CLI Exception Trace" width="100%"> |
| 44 | +</p> |
| 45 | + |
| 46 | +--- |
| 47 | + |
| 48 | +## See It In Action |
| 49 | + |
| 50 | +### 1. Framework Boundary Protection (Laravel / Symfony) |
| 51 | +Prevent dynamic data bugs from leaking into database queries or API responses: |
| 52 | + |
| 53 | +```php |
| 54 | +namespace App\Models; |
| 55 | + |
| 56 | +use App\Enums\Role; |
| 57 | +use Illuminate\Database\Eloquent\Model; |
| 58 | + |
| 59 | +class User extends Model |
| 60 | +{ |
| 61 | + /** |
| 62 | + * @return list<int> |
| 63 | + */ |
| 64 | + public function assignableRoles(): array |
| 65 | + { |
| 66 | + if ($this->isSuperAdmin()) { |
| 67 | + // Bug! Returns an array of Role Enum instances instead of integers: |
| 68 | + return Role::cases(); |
| 69 | + } |
| 70 | + |
| 71 | + return [Role::STAFF->value]; |
| 72 | + } |
| 73 | +} |
| 74 | + |
| 75 | +// Executing $user->assignableRoles() throws: |
| 76 | +// TypePHP\Exception\TypeError: User::assignableRoles(): Return value[0] must be of type int, App\Enums\Role returned |
| 77 | +``` |
| 78 | + |
| 79 | +### 2. True Runtime Generics with Memory State |
| 80 | +Define generic templates and TypePHP tracks their state per object instance in memory using native `\WeakMap`: |
| 81 | + |
| 82 | +```php |
| 83 | +/** |
| 84 | + * @template T |
| 85 | + */ |
| 86 | +class Collection |
| 87 | +{ |
| 88 | + /** @param T $item */ |
| 89 | + public function add(mixed $item): void { /* ... */ } |
| 90 | +} |
| 91 | + |
| 92 | +// Prebind T = User to this specific instance in WeakMap memory |
| 93 | +/** @var Collection<User> $users */ |
| 94 | +$users = new Collection(); |
| 95 | + |
| 96 | +$users->add(new User('Alice')); // Valid |
| 97 | + |
| 98 | +$users->add(new Product('SKU-100')); |
| 99 | +// Throws TypeError: Argument $item (template T = User) must be of type User, Product given |
| 100 | +``` |
| 101 | + |
| 102 | +### 3. Array Shapes & Constant Extractions |
| 103 | +Enforce strict associative array structures and constant key/value extractions: |
| 104 | + |
| 105 | +```php |
| 106 | +namespace App\Services; |
| 107 | + |
| 108 | +use App\Database\DriverManager; |
| 109 | + |
| 110 | +/** |
| 111 | + * @phpstan-type ConnectionParams array{ |
| 112 | + * driver: key-of<DriverManager::DRIVER_MAP>, |
| 113 | + * driverClass?: value-of<DriverManager::DRIVER_MAP> |
| 114 | + * } |
| 115 | + */ |
| 116 | +class DatabaseService |
| 117 | +{ |
| 118 | + /** |
| 119 | + * @param ConnectionParams $params |
| 120 | + */ |
| 121 | + public function connect(array $params): void |
| 122 | + { |
| 123 | + // ... |
| 124 | + } |
| 125 | +} |
| 126 | + |
| 127 | +$service = new DatabaseService(); |
| 128 | + |
| 129 | +$service->connect(['driver' => 'pdo_mysql']); // Valid |
| 130 | + |
| 131 | +$service->connect(['driver' => 'pdo_invalid']); |
| 132 | +// Throws TypeError: Argument $params['driver'] must be a key of DriverManager::DRIVER_MAP |
| 133 | +``` |
| 134 | + |
| 135 | +--- |
| 136 | + |
26 | 137 | ## Documentation |
27 | 138 |
|
28 | 139 | All the documentation lives on the [typephp-php.github.io/typephp website](https://typephp-php.github.io/typephp/): |
@@ -51,4 +162,4 @@ Any contributions are welcome. Feel free to open issues or submit pull requests |
51 | 162 |
|
52 | 163 | ## License |
53 | 164 |
|
54 | | -TypePHP is open-source software licensed under the [MIT License](https://choosealicense.com/licenses/mit/). |
| 165 | +TypePHP is open-source software licensed under the [MIT License](https://choosealicense.com/licenses/mit/). |
0 commit comments