eloquent / typhax
灵活的PHP类型提示语法。
Requires
- php: >=5.3
Requires (Dev)
- eloquent/phony: ^0.5
- icecave/archer: dev-develop
- phpunit/phpunit: ^4
- sami/sami: ^3
README
灵活的PHP类型提示语法。
安装和文档
- 作为 Composer 包 eloquent/typhax 提供。
- API文档 可用。
什么是Typhax?
Typhax 是一种用于在参数类型提示中指定 PHP 类型的规范,以及任何需要以人类可读形式描述类型的场合。
它扩展了现有规范在指定类型要求方面的功能,例如在 PHP 文档 和 PHPDoc 的 @param 标签 中使用的规范。
除了标量和类类型提示之外,Typhax 还允许强大的功能,包括指定数组的键和值类型,以及使用布尔逻辑的复合类型(例如 integer|float)。
支持类型
数组
array
array<keyType,valueType>
一个 数组。键类型和值类型可以可选指定。请参阅下面的 可遍历类型 部分。
等同于 is_array() 函数。
布尔值
boolean
一个 布尔值 真或假。值必须是实际的布尔值,而不是等价的整数。
等同于 is_bool() 函数。
可调用
callable
用户定义的回调函数。这正好等同于 PHP 5.4 中引入的 callable 类型提示。
可调用可以是以下之一
- 包含函数或静态类方法的名称的字符串。
- 包含对象在索引 0 处和方法名称在索引 1 处的数组。
- 包含类名称在索引 0 处和方法名称在索引 1 处的数组。
- 匿名函数。
- 具有 __invoke() 方法的对象。
- 调用 create_function() 的结果。
等同于 is_callable() 函数。
浮点数
float
一个 浮点数。值必须是真正的浮点数,而不是等价的字符串或整数。
等同于 is_float() 函数。
整数
integer
一个 整数。值必须是真正的整数,而不是等价的字符串、布尔值或任何其他类型的值。
等同于 is_int() 函数。
混合类型
mixed
mixed<keyType,valueType>
混合类型接受任何类型的任何值(包括 null)。
混合类型可以被视为 可遍历类型,如上面的第二个示例。当以这种方式使用时,混合类型表示任何可遍历的类型,例如一个 数组 或实现了 Traversable 接口的对象。这在值必须是集合,但外部类型不重要的情况下很有用。
空值
null
一个 null 值。
等同于 === null
。
对象
object
ClassName
ClassName<keyType,valueType>
第一个形式,object
,表示一个属于任何类的 对象。这等同于 is_object() 函数。
第二个形式,ClassName
,表示一个属于类 ClassName
的 对象。这包括 ClassName
的实例、从 ClassName
扩展的类的实例以及实现了 ClassName
接口的对象实例。这等同于 instanceof 操作符。
第三个形式,ClassName<keyType,valueType>
,遵循与第二个形式相同的规则,但增加了对象必须实现 Traversable 接口的要求。可以可选地指定键类型和值类型。请参阅下面的 可遍历类型 部分。
关于命名空间
命名空间解析应遵循与 PHP 源代码相同的规则。也就是说;如果类名在当前命名空间中,或者有相关的 use 语句,则可以使用简短的形式。
Cosmos 可以用于帮助在运行时解析类名。
资源
resource
resource{ofType:resourceType}
第一个形式,resource
,表示一个属于任何类型的 资源。这等同于 is_resource() 函数。
第二个形式,resource{ofType:resourceType}
,表示一个返回与 get_resource_type() 传递的 'resourceType' 相等的字符串的 资源。
流
stream
stream{readable:true,writable:true}
stream{readable:true,writable:false}
stream{readable:false,writable:true}
代表一个流资源。可读性(readable)和可写性(writable)属性决定了流模式的模式要求。
流类型等同于Typhax类型resource{ofType:stream}
。
有关更多信息,请参阅PHP文档中的fopen()关于流模式。
字符串
string
一个字符串。值必须是一个真正的字符串,而不是任何可以转换为字符串的其他类型。
等同于is_string()函数。
可转换为字符串的类型
stringable
代表任何可以转换为有用字符串表示的值的类型。这包括字符串、整数、浮点数和具有__toString()
方法的对象。
数组、布尔值、null、资源以及没有__toString()
方法的对象不满足“可转换为字符串”的条件。
元组
tuple<typeA,typeB,typeC,...>
一个元组是一个固定大小的数组值,其中每个元素都是特定类型的。
元组通常被称为一个n-元组,其中n是元素的数量。例如,一个定义了第一个元素为字符串、第二个元素为整数的2-元组看起来像tuple
。
元组数组必须是顺序的。也就是说,数组的键必须是整数,第一个键是0,后续键每个元素递增1。
例如,['foo', 1]
满足tuple
的约束。
旧类型
以下类型也已被实现,但被认为是过时的。它们主要存在是为了与PHP手册中使用的类型和伪类型保持兼容性,应努力避免使用它们。
bool
=boolean
callback
=callable
double
=float
int
=integer
long
=integer
number
=integer|float
numeric
= 等同于is_numeric()real
=float
scalar
=integer|float|string|boolean
可遍历类型
Typhax支持指定数组和可遍历对象的键和值类型。
键和值类型的规范如下
primaryType<keyType,valueType>
此规范表示一个类型为primaryType
的值,当迭代时,产生类型为keyType
的键和类型为valueType
的值。
省略可遍历类型的键类型
keyType
可以省略
primaryType<valueType>
此规范表示一个类型为primaryType
的值,当迭代时,产生从0开始的**连续整数键**,和类型为valueType
的值。
在不指定键和值类型的情况下使用array
对于array
,键和值类型都可以省略
array
此规范等同于
array<mixed,mixed>
这意味着键和值可以是任何类型。
在可遍历类型中使用 mixed
作为主类型
可遍历类型可以指定 mixed
作为主类型
mixed<keyType,valueType>
此规范表示任何可以迭代、产生类型为 keyType
的键和类型为 valueType
的值的类型。
布尔类型逻辑
Typhax 支持类型规范中的布尔逻辑。有两个运算符,管道符号(|)表示布尔或,加号符号(+)表示布尔与。
此规范
typeA|typeB
表示类型可以是 typeA
类型或 typeB
类型。一个现实世界的例子可能是 integer|float
,以接受整数或浮点数。
此规范
typeA+typeB
表示类型既是 typeA
类型又是 typeB
类型。一个现实世界的例子可能是 InterfaceA+InterfaceB
,以只接受实现 InterfaceA
和 InterfaceB
的对象。
扩展类型
:ClassName
:ClassName{attribute:value,...}
:ClassName<typeA,typeB,typeC,...>{attribute:value,...}
扩展提供了一种通过自定义逻辑来扩展 Typhax 功能的方法。
空白符
通常,Typhax 不关心类型规范中是否使用了空白符。然而,上述文档应作为推荐的风格指南。
用法
Typhax 包含一个类型表达式解析器,它生成解析类型语法树
use Eloquent\Typhax\Parser\TypeParser; use Eloquent\Typhax\Renderer\CondensedTypeRenderer; $parser = TypeParser::create(); $type = $parser->parse('primaryType<keyType,valueType>'); $renderer = CondensedTypeRenderer::create(); echo $renderer->render($type); // outputs 'primaryType<keyType,valueType>'
还包括一个比较器,用于确定两种类型是否等价
use Eloquent\Typhax\Comparator\TypeEquivalenceComparator; $typeA = $parser->parse('integer|string'); $typeB = $parser->parse('string|integer'); $typeC = $parser->parse('string|integer|null'); $comparator = TypeEquivalenceComparator::create(); var_dump($comparator->isEquivalent($typeA, $typeB)); // outputs 'bool(true)' var_dump($comparator->isEquivalent($typeB, $typeC)); // outputs 'bool(false)'