spatie / typed
用户空间中PHP类型系统的改进:泛型、类型化列表、元组和结构体
Requires
- php: ^7.1
Requires (Dev)
- larapack/dd: ^1.1
- phpunit/phpunit: ^7.1
- symfony/stopwatch: ^4.1
README
该软件包仅是关于PHP用户空间中可进行类型检查改进的一个简单概念证明。它增加了对类型推断、泛型、联合类型、类型化列表、元组和结构体的支持。由于所有操作都在用户空间中完成,因此对可用的语法有一些限制。
支持我们
我们投入了大量资源来创建最好的开源软件包。您可以通过购买我们的付费产品之一来支持我们。
我们非常感谢您从您的家乡给我们寄来明信片,并提及您正在使用我们的哪个软件包。您可以在我们的联系页面上找到我们的地址。我们将所有收到的明信片发布在我们的虚拟明信片墙上。
安装
您可以通过composer安装该软件包
composer require spatie/typed
使用方法
类型推断
集合、元组和结构体都支持推断类型。这意味着所有示例都可以不手动指定类型而使用。例如
// This collection will only allow objects of type `Post` in it. $postCollection = new Collection([new Post()]); // This tuple will keep its signature of (Point, Point). $vector = new Tuple(new Point(30, 5), new Point(120, 0)); // This struct's fields are autmoatically type checked. $struct = [ 'foo' => new Post(), 'bar' => function () { // ... }, ];
以下示例都显示了手动类型配置。在某些情况下,类型推断不够用,您必须手动定义它们。您可能也喜欢手动方法,以便更清晰。
请注意,类型可能只部分推断。元组或结构体中的某些字段可能是类型定义,其他可能是实际值。未初始化的类型在读取时将抛出错误。
类型化列表和集合
$list = new Collection(T::bool()); $list[] = new Post(); // TypeError
在构造后,可以直接使用数据初始化一个集合。
$list = (new Collection(T::string()))->set(['a', 'b', 'c']);
该软件包还提供了一些预定义的列表作为快捷方式。
$list = new IntegerList([1, 4]); $list[] = 'a'; // TypeError
泛型
泛型类型围绕类包裹,允许您为每个类不创建自定义类型。
$postList = new Collection(T::generic(Post::class)); $postList[] = 1; // TypeError
元组
$point = new Tuple(T::float(), T::float()); $point[0] = 1.5; $point[1] = 3; $point[0] = 'a'; // TypeError $point['a'] = 1; // TypeError $point[10] = 1; // TypeError
与列表类似,元组也可以使用set
函数在构造后添加一些数据。
$tuple = (new Tuple(T::string(), T::array()))->set('abc', []);
结构体
$developer = new Struct([ 'name' => T::string(), 'age' => T::int(), 'second_name' => T::nullable(T::string()), ]); $developer['name'] = 'Brent'; $developer['second_name'] = 'John'; $developer->set([ 'name' => 'BrenDt', 'age' => 23, 'second_name' => null, ]); echo $developer->age; $developer->name = 'Brent'; $developer->age = 'abc' // TypeError $developer->somethingElse = 'abc' // TypeError
可空类型
可空类型可以通过两种功能上相同的方式定义
$list1 = new Collection(T::int()->nullable()); $list2 = new Collection(T::nullable(T::int()));
联合类型
联合类型意味着多个类型的集合。
$list = new Collection(T::union(T::int(), T::float())); $list[] = 1; $list[] = 1.1; $list[] = 'abc'; // TypeError
联合类型也可以是可空的,并包含泛型。
不包括的内容
- 正确的语法。
- 泛型类型的IDE自动完成。
- 防止标量类型之间的类型转换。
- 在函数中为泛型类型提供类型提示。
创建自己的类型
可以使用 GenericType
或 T::generic()
来创建该类型的结构。然而,也可以在不使用泛型的情况下创建自己的类型。以 Post
为例。泛型方法无需添加自定义类型即可工作。
$postList = new Collection(T::generic(Post::class)); $postList[] = new Post(); $postList[] = 1; // TypeError
创建自己的类型时可以省略 generic
部分。
use Spatie\Typed\Type; use Spatie\Typed\Types\Nullable; class PostType implements Type { use Nullable; public function validate($post): Post { return $post; } }
现在您可以直接使用 PostType
。
$postList = new Collection(new PostType());
您也可以扩展 T
辅助器。
class T extends Spatie\Typed\T { public static function post(): PostType { return new PostType(); } } // ... $postList = new Collection(T::post());
Nullable
特性添加了以下简单片段,以便在使用时使类型可空。
public function nullable(): NullType { return new NullType($this); }
注意:建议您在自己的类型类中实现
__toString
。
扩展数据结构
您可以自由扩展现有的数据结构。例如,您可以创建类似这样的简写元组
class Coordinates extends Tuple { public function __construct(int $x, int $y) { parent::__construct(T::int(), T::int()); $this[0] = $x; $this[1] = $y; } }
我们为什么构建这个?
PHP 具有非常弱化的类型系统。这既是优点也是缺点。弱类型系统提供了一个非常灵活的开发平台,而强类型系统可以防止某些错误在运行时发生。
在其当前状态下,PHP 的类型系统尚未准备好实现许多人想要的一些特性。例如,查看一些提议更改当前类型系统的 RFC。
- 泛型:https://wiki.php.net/rfc/generics
- 类型属性:https://wiki.php.net/rfc/typed-properties
- 只读属性:https://wiki.php.net/rfc/readonly_properties
其中一些已经被拒绝,因为运行时性能问题或实现困难。此包是一个思想实验,假设这些特性在 PHP 中实现,并使用原生语法使用。
例如,以下语法会比此包的当前方式更受欢迎。
$postList = new Collection<Post>(); // vs. $postList[] = new Collection(T::generic(Post::class));
无论如何,这些都是值得思考的问题。也许 PHP 的类型系统现在就很好?您可以在我的博客上了解更多关于类型安全的信息 在这里。
贡献
有关详细信息,请参阅 CONTRIBUTING。
安全
如果您发现任何与安全相关的问题,请通过电子邮件 freek@spatie.be 而不是使用问题跟踪器。
Postcardware
您可以自由使用此包,但如果它进入您的生产环境,我们非常希望您能从您的家乡寄给我们一张明信片,说明您正在使用我们的哪个包。
我们的地址是:Spatie,Kruikstraat 22,2018 安特卫普,比利时。
我们将所有收到的明信片 发布在我们的公司网站上。
鸣谢
许可证
MIT 许可证(MIT)。有关更多信息,请参阅 许可证文件。