Skip to content

Commit deb572f

Browse files
authored
Merge pull request #4 from typephp-php/create-documentation
Create documentation
2 parents 6a0e654 + 86ce2fd commit deb572f

102 files changed

Lines changed: 6255 additions & 2438 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/FUNDING.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
github: [rcalicdan]

.github/workflows/ci.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
permissions:
12+
contents: read
13+
14+
jobs:
15+
test:
16+
name: PHP ${{ matrix.php }} (${{ matrix.os }})
17+
runs-on: ${{ matrix.os }}
18+
19+
strategy:
20+
fail-fast: false
21+
matrix:
22+
os: [ubuntu-latest, windows-latest, macos-latest]
23+
php: ['8.2', '8.3', '8.4', '8.5']
24+
25+
steps:
26+
- name: Checkout Code
27+
uses: actions/checkout@v4
28+
29+
- name: Setup PHP
30+
uses: shivammathur/setup-php@v2
31+
with:
32+
php-version: ${{ matrix.php }}
33+
extensions: dom, mbstring, zip, libxml, json, tokenizer, fileinfo
34+
coverage: none
35+
36+
- name: Install Dependencies
37+
uses: ramsey/composer-install@v3
38+
with:
39+
dependency-versions: ${{ matrix.php == '8.2' && 'lowest' || 'highest' }}
40+
41+
- name: Run Static Analysis (PHPStan)
42+
run: ./vendor/bin/phpstan analyse --no-progress
43+
if: matrix.os == 'ubuntu-latest' && matrix.php == '8.3'
44+
45+
- name: Run Test Suite (Pest)
46+
run: ./vendor/bin/pest --ci

.github/workflows/deploy-docs.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: Deploy Documentation
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- 'docs/**'
9+
- '.github/workflows/deploy-docs.yml'
10+
11+
permissions:
12+
contents: read
13+
pages: write
14+
id-token: write
15+
16+
concurrency:
17+
group: 'pages'
18+
cancel-in-progress: true
19+
20+
jobs:
21+
deploy:
22+
environment:
23+
name: github-pages
24+
url: ${{ steps.deployment.outputs.page_url }}
25+
runs-on: ubuntu-latest
26+
steps:
27+
- name: Checkout
28+
uses: actions/checkout@v4
29+
30+
- name: Setup Node.js
31+
uses: actions/setup-node@v4
32+
with:
33+
node-version: 20
34+
cache: npm
35+
36+
- name: Install dependencies
37+
run: npm ci
38+
39+
- name: Build with VitePress
40+
run: npm run docs:build
41+
42+
- name: Upload artifact
43+
uses: actions/upload-pages-artifact@v3
44+
with:
45+
path: docs/.vitepress/dist
46+
47+
- name: Deploy to GitHub Pages
48+
id: deployment
49+
uses: actions/deploy-pages@v4

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
composer.lock
22
/vendor
33
/.vscode
4-
/var
4+
/var
5+
/node_modules
6+
package-lock.json
7+
docs/.vitepress/cache
8+
docs/.vitepress/dist

composer.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "typephp/typephp",
3-
"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.",
3+
"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.",
44
"type": "library",
55
"license": "MIT",
66
"keywords": [
@@ -25,13 +25,13 @@
2525
}
2626
],
2727
"require": {
28-
"php": ">=8.1",
28+
"php": "^8.1",
2929
"phpstan/phpdoc-parser": "^2.0",
3030
"nikic/php-parser": "^5.0"
3131
},
3232
"require-dev": {
3333
"laravel/pint": "^1.10",
34-
"pestphp/pest": "^2.34 || ^3.0 || ^4.0",
34+
"pestphp/pest": "^2.0 || ^3.0 || ^4.0",
3535
"phpstan/phpstan": "^2.1",
3636
"phpstan/phpstan-strict-rules": "^2.0",
3737
"phpstan/extension-installer": "^1.4"

docs/.vitepress/config.mts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { defineConfig } from 'vitepress'
2+
3+
export default defineConfig({
4+
title: "TypePHP",
5+
description: "Runtime Type Enforcement for PHP.",
6+
themeConfig: {
7+
siteTitle: "TypePHP",
8+
nav: [
9+
{ text: 'Home', link: '/' },
10+
{ text: 'Documentation', link: '/getting-started/installation' },
11+
{ text: 'Architecture', link: '/architecture/how-it-works' },
12+
{ text: 'CLI', link: '/production/cache-commands' },
13+
{ text: 'GitHub', link: 'https://github.com/typephp-php/typephp' }
14+
],
15+
sidebar: [
16+
{
17+
text: 'Getting Started',
18+
items: [
19+
{ text: 'Installation', link: '/getting-started/installation' },
20+
{ text: 'Quick Start', link: '/getting-started/quick-start' },
21+
{ text: 'Configuration', link: '/getting-started/configuration' },
22+
]
23+
},
24+
{
25+
text: 'Architecture',
26+
items: [
27+
{ text: 'How It Works', link: '/architecture/how-it-works' },
28+
]
29+
},
30+
{
31+
text: 'Core Concepts',
32+
items: [
33+
{ text: 'Function Contracts', link: '/core-concepts/function-contracts' },
34+
{ text: 'Inline Variables', link: '/core-concepts/inline-variables' },
35+
{ text: 'Property Validation', link: '/core-concepts/property-validation' },
36+
{ text: 'Generics & Bounds', link: '/core-concepts/generics-and-bounds' },
37+
{ text: 'Type Aliases', link: '/core-concepts/type-aliases' },
38+
]
39+
},
40+
{
41+
text: 'Supported Types',
42+
items: [
43+
{ text: 'Primitives & Scalars', link: '/supported-types/primitives-and-scalars' },
44+
{ text: 'Arrays & Shapes', link: '/supported-types/arrays-and-shapes' },
45+
{ text: 'Callables & Closures', link: '/supported-types/callables-and-closures' },
46+
{ text: 'Iterators & Generators', link: '/supported-types/iterators-and-generators' },
47+
{ text: 'Unions, Intersections & Conditionals', link: '/supported-types/unions-intersections-and-conditionals' },
48+
]
49+
},
50+
{
51+
text: 'Advanced Features',
52+
items: [
53+
{ text: 'Liskov & Inheritance', link: '/advanced/liskov-and-inheritance' },
54+
{ text: 'Vendor Isolation', link: '/advanced/vendor-and-path-filtering' },
55+
{ text: 'Ignore Annotations', link: '/advanced/ignore-annotations' },
56+
{ text: 'Extensions', link: '/advanced/extensions' },
57+
{ text: 'Exception Handling', link: '/advanced/exception-handling' },
58+
{ text: 'Troubleshooting & FAQ', link: '/advanced/troubleshooting' }
59+
]
60+
},
61+
{
62+
text: 'Production & Performance',
63+
items: [
64+
{ text: 'Production Readiness', link: '/production/production-readiness' },
65+
{ text: 'Cache CLI Commands', link: '/production/cache-commands' },
66+
{ text: 'Performance Considerations', link: '/production/performance-considerations' },
67+
]
68+
}
69+
],
70+
socialLinks: [
71+
{ icon: 'github', link: 'https://github.com/typephp-php/typephp' }
72+
],
73+
search: {
74+
provider: 'local'
75+
}
76+
}
77+
})
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# Exception Handling
2+
3+
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.
4+
5+
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.
6+
7+
---
8+
9+
## The Exception Class Hierarchy
10+
11+
All contract violations in TypePHP instantiate `TypePHP\Exception\TypeError`, which extends PHP's native `\TypeError`:
12+
13+
```
14+
\Throwable
15+
└── \Error
16+
└── \TypeError
17+
└── TypePHP\Exception\TypeError
18+
```
19+
20+
---
21+
22+
## Dual Catching Modes
23+
24+
Because `TypePHP\Exception\TypeError` extends native `\TypeError`, you can choose how broadly or narrowly to catch type failures:
25+
26+
### 1. Polymorphic Catching (`catch (\TypeError $e)`)
27+
28+
Catches both native PHP engine type errors (such as passing a string into a native `int` type hint) and TypePHP contract failures:
29+
30+
```php
31+
try {
32+
processUser(-50);
33+
} catch (\TypeError $e) {
34+
// Catches both native PHP TypeErrors and TypePHP contract failures!
35+
}
36+
```
37+
38+
### 2. Specific Contract Catching (`catch (\TypePHP\Exception\TypeError $e)`)
39+
40+
Specifically catches TypePHP contract violations while allowing native PHP engine errors to bubble up separately:
41+
42+
```php
43+
use TypePHP\Exception\TypeError as TypePHPTypeError;
44+
45+
try {
46+
processUser(-50);
47+
} catch (TypePHPTypeError $e) {
48+
// Catches ONLY TypePHP contract violations!
49+
} catch (\TypeError $e) {
50+
// Catches native PHP engine type errors!
51+
}
52+
```
53+
54+
---
55+
56+
## Call-Site Trace Attribution
57+
58+
When a function parameter or callback argument fails type validation, TypePHP automatically rewrites the exception's file and line attributes.
59+
60+
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.
61+
62+
---
63+
64+
## HTTP API Payload Validation (Framework-Agnostic 422 Responses)
65+
66+
`TypePHP\Exception\TypeError` is especially useful when validating external HTTP request payloads at application boundaries.
67+
68+
When dynamic request data fails contract validation, you can catch `TypePHPTypeError` and return a clean HTTP `422 Unprocessable Entity` response:
69+
70+
```php
71+
namespace App\Http;
72+
73+
use App\Services\UserService;
74+
use TypePHP\Exception\TypeError as TypePHPTypeError;
75+
76+
class UserApiController
77+
{
78+
public function __construct(private UserService $userService) {}
79+
80+
public function handleRequest(array $requestData): array
81+
{
82+
try {
83+
// UserService enforces @param array{id: positive-int, email: non-empty-string}
84+
$this->userService->registerUser($requestData);
85+
86+
return [
87+
'status' => 200,
88+
'body' => ['message' => 'User registered successfully'],
89+
];
90+
} catch (TypePHPTypeError $e) {
91+
// Convert TypePHP contract failure into an HTTP 422 response
92+
return [
93+
'status' => 422,
94+
'body' => [
95+
'error' => 'Unprocessable Entity',
96+
'message' => $e->getMessage(),
97+
],
98+
];
99+
}
100+
}
101+
}
102+
```
103+
104+
---
105+
106+
## Human-Readable Error Formatting
107+
108+
TypePHP's `TypeFormatter` formats invalid values into descriptive human-readable strings inside exception messages:
109+
110+
* **Integers:** `negative int (-50)`, `zero int (0)`, `int (42)`
111+
* **Strings:** `empty string ('')`, `string 'this_is_a_very_lo...'`
112+
* **Booleans:** `bool (true)`, `bool (false)`
113+
* **Arrays:** `empty array ([])`, `list (3 items)`, `associative array (key 'id')`
114+
* **Objects:** Class FQCN (e.g., `App\Models\Product`)

0 commit comments

Comments
 (0)