Skip to content

Repository files navigation

TypePHP

No transpilation. No build steps. No C-extensions.
Drop TypePHP into your existing codebase and let your DocBlocks scream when types fail.

Build Status Code Coverage Latest Stable Version Total Downloads License PHP Version PHPStan Level MAX


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.

Read the full TypePHP documentation »


Installation

Install TypePHP as a development dependency via Composer:

composer require typephp/typephp --dev

Note: TypePHP boots automatically via Composer's autoloader. No service providers, bootstrap edits, or framework configurations are required.


Quick Start

1. Initialize Configuration (Optional)

Generate a default typephp.php configuration file in your project root:

vendor/bin/typephp config:init

2. Write Standard DocBlocks

Annotate your functions, methods, and classes with standard static analysis DocBlocks:

namespace App\Services;

class PaymentService
{
    /**
     * @param positive-int $amount
     * @param array{gateway: 'stripe'|'paypal', currency: non-empty-string} $options
     * @return non-empty-string
     */
    public function charge(int $amount, array $options): string
    {
        return "Transaction successful";
    }
}

3. Run Your Application or Tests

If your application runs through an entry point where require 'vendor/autoload.php' is declared (such as a web framework's public/index.php, CLI commands, or test runners like Pest and PHPUnit), TypePHP runs automatically and transparently in the background.

Simply run your tests or use your local development server (Laravel, Symfony, FrankenPHP, PHP-FPM). TypePHP immediately intercepts and enforces all parameter, return, shape, and generic contracts in real time.


Executing Standalone Scripts (CLI Runner)

For standalone, single-execution PHP scripts that do not have an explicit autoloader entry point, run them directly with the TypePHP CLI binary:

vendor/bin/typephp script.php

Type-Checking Files Anywhere ("*" Wildcard Glob)

By default, TypePHP checks standard application folders (src/**, app/**, tests/**). To type-check PHP files anywhere in your project root while still respecting your excluded folders, set the "*" wildcard glob in typephp.php:

// typephp.php
return [
    'include' => [
        '*', // Intercepts and type-checks PHP files anywhere in the project
    ],
    'exclude' => [
        'vendor/**',
        'storage/**',
        'var/**',
        'cache/**',
    ],
];

Live Diagnostics (Zero Line-Drift)

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:

Web Framework Trace (Laravel Ignition)

Laravel Ignition Exception Trace

Web Framework Trace (Symfony ErrorHandler)

Symfony ErrorHandler Exception Trace

CLI Test Runner Trace (Pest PHP)

Pest CLI Exception Trace


See It In Action

1. Framework Boundary Protection (Laravel / Symfony)

Prevent dynamic data bugs from leaking into database queries or API responses:

namespace App\Models;

use App\Enums\Role;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * @return list<int>
     */
    public function assignableRoles(): array
    {
        if ($this->isSuperAdmin()) {
            // Bug! Returns an array of Role Enum instances instead of integers:
            return Role::cases(); 
        }

        return [Role::STAFF->value];
    }
}

// Executing $user->assignableRoles() throws:
// TypePHP\Exception\TypeError: User::assignableRoles(): Return value[0] must be of type int, App\Enums\Role returned

2. True Runtime Generics with Memory State

Define generic templates and TypePHP tracks their state per object instance in memory using native \WeakMap:

/**
 * @template T
 */
class Collection 
{
    /** @param T $item */
    public function add(mixed $item): void { /* ... */ }
}

// Prebind T = User to this specific instance in WeakMap memory
/** @var Collection<User> $users */
$users = new Collection();

$users->add(new User('Alice')); // Valid

$users->add(new Product('SKU-100')); 
// Throws TypeError: Argument $item (template T = User) must be of type User, Product given

3. Array Shapes & Constant Extractions

Enforce strict associative array structures and constant key/value extractions:

namespace App\Services;

use App\Database\DriverManager;

/**
 * @phpstan-type ConnectionParams array{
 *     driver: key-of<DriverManager::DRIVER_MAP>,
 *     driverClass?: value-of<DriverManager::DRIVER_MAP>
 * }
 */
class DatabaseService
{
    /**
     * @param ConnectionParams $params
     */
    public function connect(array $params): void
    {
        // ...
    }
}

$service = new DatabaseService();

$service->connect(['driver' => 'pdo_mysql']); // Valid

$service->connect(['driver' => 'pdo_invalid']);
// Throws TypeError: Argument $params['driver'] must be a key of DriverManager::DRIVER_MAP

Documentation

All the documentation lives on the typephp-php.github.io/docs website:


Inspiration

TypePHP is conceptually inspired by Python's Beartype, bringing transparent runtime type enforcement for type annotations to the PHP ecosystem without any decorators or attributes.


Sponsors

Want to support the open-source development and maintenance of TypePHP? Sponsor me on GitHub »


Contributing

Any contributions are welcome. Feel free to open issues or submit pull requests on GitHub.


License

TypePHP is open-source software licensed under the MIT License.

About

Pure PHP Transparent Runtime Enforcement of PHPdoctype, with support for generics, type-arrays,

Resources

Contributing

Security policy

Stars

46 stars

Watchers

6 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages