Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
dadca04
Add initial documentation files and configuration setup for TypePHP
rcalicdan Aug 6, 2026
1e0a218
Add comprehensive documentation and configuration setup for TypePHP, …
rcalicdan Aug 6, 2026
3e5a519
Add more documentations
rcalicdan Aug 6, 2026
6ff1e94
Enhance Quick Start Guide with detailed recommendations for using Typ…
rcalicdan Aug 6, 2026
df4c4d8
Add clone instance generics support. Add comprehensive documentation …
rcalicdan Aug 7, 2026
d1597b7
Add comprehensive documentation for arrays, shapes, callables, and pr…
rcalicdan Aug 7, 2026
63d3997
Add documentation for iterators and generators, including lazy valida…
rcalicdan Aug 7, 2026
49dd16b
set up vitepress for docsite launching
rcalicdan Aug 8, 2026
43a4675
Add troubleshooting and FAQ documentation; enhance index and quick st…
rcalicdan Aug 8, 2026
0423fa1
satisfy all max level phpstan checks
rcalicdan Aug 8, 2026
838eaa9
Add CI workflow and funding configuration; update tests for property …
rcalicdan Aug 8, 2026
e706fe3
Enhance documentation for float literals; add tests for precision and…
rcalicdan Aug 8, 2026
a9d7a30
remove internal testing files
rcalicdan Aug 8, 2026
ebcddc7
Add execution order note to quick start guide for clarity on type hin…
rcalicdan Aug 8, 2026
b59a95c
Enhance quick start guide with detailed explanations on TypePHP's fun…
rcalicdan Aug 8, 2026
52c5ef2
Update composer.json description and refine pestphp/pest version cons…
rcalicdan Aug 8, 2026
189ccd0
Update PHP version constraint in composer.json to use caret notation
rcalicdan Aug 8, 2026
77f1ec7
Refactor CI workflow to remove caching steps and streamline dependenc…
rcalicdan Aug 8, 2026
6789199
Fix syntax error in CacheManager by removing incorrect type declarati…
rcalicdan Aug 8, 2026
a73916c
Update composer.json to refine PHP and package version constraints fo…
rcalicdan Aug 8, 2026
1286bba
Remove code style check step from CI workflow for PHP 8.3
rcalicdan Aug 8, 2026
445d625
Refactor CI workflow to streamline dependency installation for PHP 8.1
rcalicdan Aug 8, 2026
6ab3c9a
Refactor CI workflow and update dependencies for improved compatibility
rcalicdan Aug 8, 2026
926d7d8
Update CI workflow to remove PHP 8.1 and adjust dependency versions f…
rcalicdan Aug 8, 2026
86ce2fd
Add PHP version check to PropertyHookInjectorTest for compatibility
rcalicdan Aug 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
github: [rcalicdan]
46 changes: 46 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: CI

on:
push:
branches:
- main
pull_request:
branches:
- main

permissions:
contents: read

jobs:
test:
name: PHP ${{ matrix.php }} (${{ matrix.os }})
runs-on: ${{ matrix.os }}

strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
php: ['8.2', '8.3', '8.4', '8.5']

steps:
- name: Checkout Code
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: dom, mbstring, zip, libxml, json, tokenizer, fileinfo
coverage: none

- name: Install Dependencies
uses: ramsey/composer-install@v3
with:
dependency-versions: ${{ matrix.php == '8.2' && 'lowest' || 'highest' }}

- name: Run Static Analysis (PHPStan)
run: ./vendor/bin/phpstan analyse --no-progress
if: matrix.os == 'ubuntu-latest' && matrix.php == '8.3'

- name: Run Test Suite (Pest)
run: ./vendor/bin/pest --ci
49 changes: 49 additions & 0 deletions .github/workflows/deploy-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Deploy Documentation

on:
push:
branches:
- main
paths:
- 'docs/**'
- '.github/workflows/deploy-docs.yml'

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: 'pages'
cancel-in-progress: true

jobs:
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- name: Install dependencies
run: npm ci

- name: Build with VitePress
run: npm run docs:build

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: docs/.vitepress/dist

- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
composer.lock
/vendor
/.vscode
/var
/var
/node_modules
package-lock.json
docs/.vitepress/cache
docs/.vitepress/dist
6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "typephp/typephp",
"description": "Zero-cost runtime type checker for PHP. Enforces PHPDoc annotations including generics, typed arrays, array shapes, and advanced types at runtime in development and testing.",
"description": "Zero-cost runtime type checker for PHP. Enforces PHPDoc annotations including generics, typed arrays, array shapes, and advanced types at runtime in development and production.",
"type": "library",
"license": "MIT",
"keywords": [
Expand All @@ -25,13 +25,13 @@
}
],
"require": {
"php": ">=8.1",
"php": "^8.1",
"phpstan/phpdoc-parser": "^2.0",
"nikic/php-parser": "^5.0"
},
"require-dev": {
"laravel/pint": "^1.10",
"pestphp/pest": "^2.34 || ^3.0 || ^4.0",
"pestphp/pest": "^2.0 || ^3.0 || ^4.0",
"phpstan/phpstan": "^2.1",
"phpstan/phpstan-strict-rules": "^2.0",
"phpstan/extension-installer": "^1.4"
Expand Down
77 changes: 77 additions & 0 deletions docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { defineConfig } from 'vitepress'

export default defineConfig({
title: "TypePHP",
description: "Runtime Type Enforcement for PHP.",
themeConfig: {
siteTitle: "TypePHP",
nav: [
{ text: 'Home', link: '/' },
{ text: 'Documentation', link: '/getting-started/installation' },
{ text: 'Architecture', link: '/architecture/how-it-works' },
{ text: 'CLI', link: '/production/cache-commands' },
{ text: 'GitHub', link: 'https://github.com/typephp-php/typephp' }
],
sidebar: [
{
text: 'Getting Started',
items: [
{ text: 'Installation', link: '/getting-started/installation' },
{ text: 'Quick Start', link: '/getting-started/quick-start' },
{ text: 'Configuration', link: '/getting-started/configuration' },
]
},
{
text: 'Architecture',
items: [
{ text: 'How It Works', link: '/architecture/how-it-works' },
]
},
{
text: 'Core Concepts',
items: [
{ text: 'Function Contracts', link: '/core-concepts/function-contracts' },
{ text: 'Inline Variables', link: '/core-concepts/inline-variables' },
{ text: 'Property Validation', link: '/core-concepts/property-validation' },
{ text: 'Generics & Bounds', link: '/core-concepts/generics-and-bounds' },
{ text: 'Type Aliases', link: '/core-concepts/type-aliases' },
]
},
{
text: 'Supported Types',
items: [
{ text: 'Primitives & Scalars', link: '/supported-types/primitives-and-scalars' },
{ text: 'Arrays & Shapes', link: '/supported-types/arrays-and-shapes' },
{ text: 'Callables & Closures', link: '/supported-types/callables-and-closures' },
{ text: 'Iterators & Generators', link: '/supported-types/iterators-and-generators' },
{ text: 'Unions, Intersections & Conditionals', link: '/supported-types/unions-intersections-and-conditionals' },
]
},
{
text: 'Advanced Features',
items: [
{ text: 'Liskov & Inheritance', link: '/advanced/liskov-and-inheritance' },
{ text: 'Vendor Isolation', link: '/advanced/vendor-and-path-filtering' },
{ text: 'Ignore Annotations', link: '/advanced/ignore-annotations' },
{ text: 'Extensions', link: '/advanced/extensions' },
{ text: 'Exception Handling', link: '/advanced/exception-handling' },
{ text: 'Troubleshooting & FAQ', link: '/advanced/troubleshooting' }
]
},
{
text: 'Production & Performance',
items: [
{ text: 'Production Readiness', link: '/production/production-readiness' },
{ text: 'Cache CLI Commands', link: '/production/cache-commands' },
{ text: 'Performance Considerations', link: '/production/performance-considerations' },
]
}
],
socialLinks: [
{ icon: 'github', link: 'https://github.com/typephp-php/typephp' }
],
search: {
provider: 'local'
}
}
})
114 changes: 114 additions & 0 deletions docs/advanced/exception-handling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# Exception Handling

If you run TypePHP in live production applications—especially for validating external HTTP API payloads, webhooks, or dynamic database records—catching `TypePHP\Exception\TypeError` gives you a clean way to intercept data validation failures gracefully without letting exceptions crash your application.

TypePHP provides a custom exception class, `TypePHP\Exception\TypeError`, designed for both polymorphic compatibility with PHP's native type system and surgical error handling at application boundaries.

---

## The Exception Class Hierarchy

All contract violations in TypePHP instantiate `TypePHP\Exception\TypeError`, which extends PHP's native `\TypeError`:

```
\Throwable
└── \Error
└── \TypeError
└── TypePHP\Exception\TypeError
```

---

## Dual Catching Modes

Because `TypePHP\Exception\TypeError` extends native `\TypeError`, you can choose how broadly or narrowly to catch type failures:

### 1. Polymorphic Catching (`catch (\TypeError $e)`)

Catches both native PHP engine type errors (such as passing a string into a native `int` type hint) and TypePHP contract failures:

```php
try {
processUser(-50);
} catch (\TypeError $e) {
// Catches both native PHP TypeErrors and TypePHP contract failures!
}
```

### 2. Specific Contract Catching (`catch (\TypePHP\Exception\TypeError $e)`)

Specifically catches TypePHP contract violations while allowing native PHP engine errors to bubble up separately:

```php
use TypePHP\Exception\TypeError as TypePHPTypeError;

try {
processUser(-50);
} catch (TypePHPTypeError $e) {
// Catches ONLY TypePHP contract violations!
} catch (\TypeError $e) {
// Catches native PHP engine type errors!
}
```

---

## Call-Site Trace Attribution

When a function parameter or callback argument fails type validation, TypePHP automatically rewrites the exception's file and line attributes.

Instead of blaming internal library files, `ErrorFactory` filters out internal frames and attributes `$e->file` and `$e->line` directly to **the exact line of code in the caller file where the invalid argument was passed**, matching native PHP engine behavior.

---

## HTTP API Payload Validation (Framework-Agnostic 422 Responses)

`TypePHP\Exception\TypeError` is especially useful when validating external HTTP request payloads at application boundaries.

When dynamic request data fails contract validation, you can catch `TypePHPTypeError` and return a clean HTTP `422 Unprocessable Entity` response:

```php
namespace App\Http;

use App\Services\UserService;
use TypePHP\Exception\TypeError as TypePHPTypeError;

class UserApiController
{
public function __construct(private UserService $userService) {}

public function handleRequest(array $requestData): array
{
try {
// UserService enforces @param array{id: positive-int, email: non-empty-string}
$this->userService->registerUser($requestData);

return [
'status' => 200,
'body' => ['message' => 'User registered successfully'],
];
} catch (TypePHPTypeError $e) {
// Convert TypePHP contract failure into an HTTP 422 response
return [
'status' => 422,
'body' => [
'error' => 'Unprocessable Entity',
'message' => $e->getMessage(),
],
];
}
}
}
```

---

## Human-Readable Error Formatting

TypePHP's `TypeFormatter` formats invalid values into descriptive human-readable strings inside exception messages:

* **Integers:** `negative int (-50)`, `zero int (0)`, `int (42)`
* **Strings:** `empty string ('')`, `string 'this_is_a_very_lo...'`
* **Booleans:** `bool (true)`, `bool (false)`
* **Arrays:** `empty array ([])`, `list (3 items)`, `associative array (key 'id')`
* **Objects:** Class FQCN (e.g., `App\Models\Product`)
Loading
Loading