PHPackages                             forrest79/phpstan-narrow-types - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. forrest79/phpstan-narrow-types

Abandoned → [forrest79/type-validator](/?search=forrest79%2Ftype-validator)Phpstan-extension[Utility &amp; Helpers](/categories/utility)

forrest79/phpstan-narrow-types
==============================

TypeValidator provides functionality to check types with PHP Doc syntax in runtime and narrow types for PHPStan.

v1.2.1(3mo ago)6521BSD-3-ClausePHPPHP ^8.3CI failing

Since Apr 30Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/forrest79/type-validator)[ Packagist](https://packagist.org/packages/forrest79/phpstan-narrow-types)[ RSS](/packages/forrest79-phpstan-narrow-types/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (8)Versions (11)Used By (0)

TypeValidator
=============

[](#typevalidator)

[![Latest Stable Version](https://camo.githubusercontent.com/80f586ce871da047cc95f1224d87d241039869975609827b08908c1403b577cc/68747470733a2f2f706f7365722e707567782e6f72672f666f727265737437392f747970652d76616c696461746f722f76)](//packagist.org/packages/forrest79/type-validator)[![Monthly Downloads](https://camo.githubusercontent.com/01165eee607da21e7e125d5eb2575c6c7f5e06e58003585aabdda167b84a78a4/68747470733a2f2f706f7365722e707567782e6f72672f666f727265737437392f747970652d76616c696461746f722f642f6d6f6e74686c79)](//packagist.org/packages/forrest79/type-validator)[![License](https://camo.githubusercontent.com/14406fd50ce3a7348714519c79be572e183f78ee8bd99de8e6feda87b9a2672d/68747470733a2f2f706f7365722e707567782e6f72672f666f727265737437392f747970652d76616c696461746f722f6c6963656e7365)](//packagist.org/packages/forrest79/type-validator)[![Build](https://github.com/forrest79/type-validator/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/forrest79/type-validator/actions/workflows/build.yml)[![codecov](https://camo.githubusercontent.com/c29135dcf86ba6d0af8889e14dd33b3c82b46d71e4134d686019f1659bf51fbe/68747470733a2f2f636f6465636f762e696f2f67682f666f727265737437392f747970652d76616c696461746f722f67726170682f62616467652e7376673f746f6b656e3d53594a434a58435a3649)](https://codecov.io/gh/forrest79/type-validator)

Introduction
------------

[](#introduction)

Validates types using PHP Doc descriptions and narrows types for [PHPStan](https://phpstan.org/).

Imagine you're loading data from some external source. For PHP, this is mostly `mixed` (or some other common type like `array`/`object`), and PHPStan is unhappy with this. If data is some simple type, most of us will add something like:

```
assert(is_int($data)); // if we know, there will be always an int
if (!is_int($data)) throw new InvalidDataException(); // if we want to check this also in runtime
```

Both make PHPStan happy, and you code is also tested (the first example mostly in dev environment, where the assertion is on).

But when the loaded data is a complex type like `list`.

Checking this at runtime and making PHPStan happy is now harder. The goal of this library is to make this as simple as `assert(is_int($data))`.

Use `assert(is_type($data, 'list'))` and the variable is really checked for the correct type at runtime, and the type is also narrowed for PHPStan.

> Code coverage is computed without PHPStan extension - only the PHP runtime part.

Installation
------------

[](#installation)

To use this extension, require it in [Composer](https://getcomposer.org/):

```
composer require --dev forrest79/type-validator

```

> You probably only want this extension for development, but it can also be used in production (omit `--dev`).

Using
-----

[](#using)

There is one global function `is_type(mixed $var, string $type)` and static methods `Forrest79\TypeValidator::isType(mixed $var, string $type): bool` or `Forrest79\TypeValidator::checkType(mixed $var, string $type): void`.

All of them really check the data in `$var` against the type description and there is corresponding PHPStan extension so PHPStan will understand, that `$var` is in described type.

The function `is_type(mixed $var, string $type)` and method `Forrest79\TypeValidator::isType(mixed $var, string $type)` return a `bool` - true if `$var` matches the `$type`, and `false` otherwise.

The Method `Forrest79\TypeValidator::checkType(mixed $var, string $type)` has no return, but it throws a `CheckException`, if `$var` does not match the `$type`.

Example:

```
$arr = [3.14, 5, 10];
assert(is_type($arr, 'list'));
assert(Forrest79\TypeValidator::isType($arr, 'list'));
Forrest79\TypeValidator::checkType($arr, 'list'));
```

With this you can replace your `@var` annotations:

```
/** @var array $arr
$arr = json_decode($data);
```

With:

```
$arr = json_decode($data);
assert(is_type($arr, 'array'));
```

The benefit is that variable `$arr` is checked for defined type.

Almost all PHPDoc types from PHPStan are supported (more information about supported types is provided later in the docs).

To use this library as PHPStan extension include `extension.neon` in your project's PHPStan config:

```
includes:
    - vendor/forrest79/type-validator/extension.neon
```

> Because of PHPStan, the type description must be a static string—nothing can be generated dynamically.

### Use in production

[](#use-in-production)

Typically, the `assert` function is disabled in production, so checks are only performed in development/test environments, and there is no need to distribute this library in a production environment.

But you can use this for validation also in your production code. Parsing PHPDoc types is not too performance-intensive. This library depends on `phpstan/phpdoc-parser` for parsing types and `nikic/php-parser` for detection fully qualified class names.

### FQN (Fully qualified names)

[](#fqn-fully-qualified-names)

Correct fully qualified names are computed from the current namespace and `use` statements, just like every other item in your PHP source files. However, if you use a `use` statement only for this library, your IDE and PHPCS may mark it as unused because they don't know about this library:

Example:

```
namespace App;

use App\Presenter; // this use is marked as unused

assert($presenter, 'class-string'); // even though it is correctly used here
```

One solution is to concatenate the type string with `::class` such as `assert($presenter, 'class-string')`. However, this looks very ugly. I prefer to use an FQN in the type description and omit the `use` statement:

```
namespace App;

assert($presenter, 'class-string');
```

### Supported PHPStan - PHPDoc Types

[](#supported-phpstan---phpdoc-types)

According to

✅ supported 🚫 not supported - doesn't make sense for variables ❌ not supported

#### Basic types ✅/🚫/❌

[](#basic-types-)

- `int`, `integer` ✅
- `string`, `non-empty-string`, `non-empty-lowercase-string`, `non-empty-uppercase-string`, `truthy-string`, `non-falsy-string`, `lowercase-string`, `uppercase-string` ✅
- `literal-string`, `non-empty-literal-string` ❌
- `numeric-string` ✅
- `__stringandstringable` (`string` or object implementing `Stringable` interface or object with `__toString()` method) ✅
- `array-key` ✅
- `bool`, `boolean`, `true`, `false` ✅
- `null` ✅
- `float`, `double` ✅
- `number`, `numeric` ✅
- `scalar`, `empty-scalar`, `non-empty-scalar` ✅
- `array`, `associative-array`, `non-empty-array` ✅
- `list`, `non-empty-list` ✅
- `iterable` ✅
- `callable`, `callable-string`, `callable-array`, `callable-object` ✅, `pure-callable` ❌
- `resource`, `open-resource`, `closed-resource` ✅
- `object` ✅
- `empty` ✅
- `mixed`, `non-empty-mixed` ✅
- `class-string`, `interface-string`, `trait-string`, `enum-string` ✅
- `void` 🚫

#### Classes and interfaces ✅

[](#classes-and-interfaces-)

#### Integer ranges ✅

[](#integer-ranges-)

- `positive-int` ✅
- `negative-int` ✅
- `non-positive-int` ✅
- `non-negative-int` ✅
- `non-zero-int` ✅
- `int` ✅
- `int` ✅
- `int` ✅

#### General arrays ✅

[](#general-arrays-)

- `Type[]` ✅
- `array` ✅
- `array` ✅
- `non-empty-array` ✅
- `non-empty-array` ✅

#### Lists ✅

[](#lists-)

- `list` ✅
- `non-empty-list` ✅

#### Key and value types of arrays and iterables ❌

[](#key-and-value-types-of-arrays-and-iterables-)

- `key-of` ❌
- `value-of` ❌
- `value-of` ❌

#### Iterables ❌ (there can be some side effect while iterate in runtime to check correct type)

[](#iterables--there-can-be-some-side-effect-while-iterate-in-runtime-to-check-correct-type)

- `iterable` ❌
- `Collection` ❌
- `Collection` ❌
- `Collection|Type[]` ❌

#### Union types ✅

[](#union-types-)

- `Type1|Type2` ✅

#### Intersection types ✅

[](#intersection-types-)

- `Type1&Type2` ✅

#### Parentheses ✅

[](#parentheses-)

- `(Type1&Type2)|Type3` ✅

#### self, static, parent and $this 🚫

[](#self-static-parent-and-this-)

- `self`, `static`, `parent` or `$this` 🚫

#### Generics ✅/🚫/❌ (some yes, some no, some doesn't make sense - concrete info can be found in the other types description)

[](#generics--some-yes-some-no-some-doesnt-make-sense---concrete-info-can-be-found-in-the-other-types-description)

#### Conditional return types 🚫

[](#conditional-return-types-)

#### Utility types for generics ❌

[](#utility-types-for-generics-)

- `template-type` ❌
- `new` ❌

#### class-string, interface-string ✅

[](#class-string-interface-string-)

- `class-string` ✅
- `interface-string` ✅

#### Global type aliases ❌

[](#global-type-aliases-)

#### Local type aliases ❌

[](#local-type-aliases-)

#### Array shapes ✅

[](#array-shapes-)

- `array{'foo': int, "bar": string}` ✅
- `array{'foo': int, "bar"?: string}` ✅
- `array{int, int}` ✅
- `array{0: int, 1?: int}` ✅
- `array{foo: int, bar: string}` ✅

#### Object shapes ✅

[](#object-shapes-)

- `object{'foo': int, "bar": string}` ✅
- `object{'foo': int, "bar"?: string}` ✅
- `object{foo: int, bar?: string}` ✅
- `object{foo: int, bar?: string}&\stdClass` ✅

#### Literals and constants ✅/❌

[](#literals-and-constants--)

- `234` ✅
- `1.0` ✅
- `'foo'|'bar'` ✅
- `Foo::SOME_CONSTANT` ❌
- `Foo::SOME_CONSTANT|Bar::OTHER_CONSTANT` ❌
- `self::SOME_*` ❌
- `Foo::*` ❌

#### Global constants ✅

[](#global-constants-)

- `SOME_CONSTANT` ✅
- `SOME_CONSTANT|OTHER_CONSTANT` ✅

#### Callables ❌ (only simple callable is supported)

[](#callables--only-simple-callable-is-supported)

- `callable(int, int): string` ❌
- `callable(int, int=): string` ❌
- `callable(int $foo, string $bar): void` ❌
- `callable(string &$bar): mixed` ❌
- `callable(float ...$floats): (int|null)` ❌
- `callable(float...): (int|null)` ❌
- `\Closure(int, int): string` ❌
- `pure-callable(int, int): string` ❌
- `pure-Closure(int, int): string` ❌

#### Bottom type 🚫

[](#bottom-type-)

- `never` 🚫
- `never-return` 🚫
- `never-returns` 🚫
- `no-return` 🚫

#### Integer masks ✅/❌

[](#integer-masks-)

- `int-mask` ✅
- `int-mask-of` ✅
- `int-mask-of` ❌

#### Offset access ❌

[](#offset-access-)

###  Health Score

47

—

FairBetter than 94% of packages

Maintenance86

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity66

Established project with proven stability

 Bus Factor1

Top contributor holds 94.3% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~111 days

Recently: every ~17 days

Total

10

Last Release

103d ago

Major Versions

v0.4 → v1.0.02025-10-07

PHP version history (2 changes)v0.1.0PHP ^8.1

v1.0.0PHP ^8.3

### Community

Maintainers

![](https://www.gravatar.com/avatar/d979cd353c6593b44b50f90ff5a5eb4be224f501a70f7cce89d0735867e488e5?d=identicon)[forrest79](/maintainers/forrest79)

---

Top Contributors

[![forrest79](https://avatars.githubusercontent.com/u/160766?v=4)](https://github.com/forrest79 "forrest79 (33 commits)")[![vrana](https://avatars.githubusercontent.com/u/117453?v=4)](https://github.com/vrana "vrana (2 commits)")

---

Tags

PHPStanvalidatorarraylisttypesnarrow

###  Code Quality

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/forrest79-phpstan-narrow-types/health.svg)

```
[![Health](https://phpackages.com/badges/forrest79-phpstan-narrow-types/health.svg)](https://phpackages.com/packages/forrest79-phpstan-narrow-types)
```

###  Alternatives

[topshelfcraft/supersort

...a super-duper sorting function for your Craft templates.

4287.1k1](/packages/topshelfcraft-supersort)[lezhnev74/pasvl

Array Validator (regular expressions for nested array, sort of)

5253.7k3](/packages/lezhnev74-pasvl)[graze/sort

A collection of array sorting transforms and functions

12289.6k2](/packages/graze-sort)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
