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 »

Quick Start Guide »


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 Runtime Enforcement of PHPdoctype, with support for generics, type-arrays,

Resources

Contributing

Security policy

Stars

18 stars

Watchers

5 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages