定制 forrest79/type-validator 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

forrest79/type-validator

Composer 安装命令:

composer require forrest79/type-validator

包简介

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

README 文档

README

Latest Stable Version Monthly Downloads License Build codecov

Introduction

Validates types using PHP Doc descriptions and narrows types for PHPStan.

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<array{type: int, dates?: array<string, \DateTime>, validator: class-string<IValidator>}>.

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<array{type: int, dates?: array<string, \DateTime>, validator: class-string<IValidator>}>')) 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

To use this extension, require it in Composer:

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

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<float|int>'));
assert(Forrest79\TypeValidator::isType($arr, 'list<float|int>'));
Forrest79\TypeValidator::checkType($arr, 'list<float|int>'));

With this you can replace your @var annotations:

/** @var array<string|int, list<Db\Row>> $arr
$arr = json_decode($data);

With:

$arr = json_decode($data);
assert(is_type($arr, 'array<string|int, list<Db\Row>>'));

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

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)

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<Presenter>'); // even though it is correctly used here

One solution is to concatenate the type string with ::class such as assert($presenter, 'class-string<\\' . Presenter::class . '>'). 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<\App\Presenter>');

Supported PHPStan - PHPDoc Types

According to https://github.com/phpstan/phpstan/blob/2.1.x/website/src/writing-php-code/phpdoc-types.md

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

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 ✅

Integer ranges ✅

  • positive-int
  • negative-int
  • non-positive-int
  • non-negative-int
  • non-zero-int
  • int<0, 100>
  • int<min, 100>
  • int<50, max>

General arrays ✅

  • Type[]
  • array<Type>
  • array<int, Type>
  • non-empty-array<Type>
  • non-empty-array<int, Type>

Lists ✅

  • list<Type>
  • non-empty-list<Type>

Key and value types of arrays and iterables ❌

  • key-of<Type::ARRAY_CONST>
  • value-of<Type::ARRAY_CONST>
  • value-of<BackedEnum>

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

  • iterable<Type>
  • Collection<Type>
  • Collection<int, Type>
  • Collection|Type[]

Union types ✅

  • Type1|Type2

Intersection types ✅

  • Type1&Type2

Parentheses ✅

  • (Type1&Type2)|Type3

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)

Conditional return types 🚫

Utility types for generics ❌

  • template-type
  • new

class-string, interface-string ✅

  • class-string<Foo>
  • interface-string<Interface>

Global type aliases ❌

Local type aliases ❌

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{'foo': int, "bar": string}
  • object{'foo': int, "bar"?: string}
  • object{foo: int, bar?: string}
  • object{foo: int, bar?: string}&\stdClass

Literals and constants ✅/❌

  • 234
  • 1.0
  • 'foo'|'bar'
  • Foo::SOME_CONSTANT
  • Foo::SOME_CONSTANT|Bar::OTHER_CONSTANT
  • self::SOME_*
  • Foo::*

Global constants ✅

  • SOME_CONSTANT
  • SOME_CONSTANT|OTHER_CONSTANT

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
  • static-closure(int, int): string
  • static-pure-closure(int, int): string

Bottom type 🚫

  • never 🚫
  • never-return 🚫
  • never-returns 🚫
  • no-return 🚫

Integer masks ✅/❌

  • int-mask<1, 2, 4>
  • int-mask-of<1|2|4>
  • int-mask-of<Foo::INT_*>

Offset access ❌

forrest79/type-validator 适用场景与选型建议

forrest79/type-validator 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 1.79k 次下载、GitHub Stars 达 6, 最近一次更新时间为 2025 年 10 月 08 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「validator」 「array」 「list」 「types」 「PHPStan」 「narrow」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 forrest79/type-validator 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 forrest79/type-validator 我们能提供哪些服务?
定制开发 / 二次开发

基于 forrest79/type-validator 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 1.79k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 6
  • 点击次数: 17
  • 依赖项目数: 1
  • 推荐数: 1

GitHub 信息

  • Stars: 6
  • Watchers: 1
  • Forks: 1
  • 开发语言: PHP

其他信息

  • 授权协议: BSD-3-Clause
  • 更新时间: 2025-10-08