jausions / php-typed-doctrine-collections
类型化的 Doctrine 集合(具有类型约束的伪数组)
v1.0.0
2018-05-03 12:31 UTC
Requires
- doctrine/collections: ^v1.5
- jausions/php-typed-collections: ^v1.0
Requires (Dev)
- fzaninotto/faker: ^v1.7
- phpunit/phpunit: ^7.0
This package is not auto-updated.
Last update: 2024-09-29 23:17:04 UTC
README
类型提示正在发展,但 PHP 7 目前仍然没有提供定义数组(即泛型)元素类型的方法。
这个库建立在 Doctrine/Collections 之上,以对添加到集合中的元素进行类型检查。我们也可以称之为强类型数组。
目标是利用类型提示来帮助防止错误,或者至少在开发周期中更早地检测到它们。
对于这个库来说,“类型”一词是广义的,指代内置的 PHP 类型、类,甚至是应用程序域类型。
安装
composer require jausions/php-typed-doctrine-collections
以下示例中隐含了 require 'vendor/autoload.php';
。
通过初始值定义类型
传递给构造函数的第一个元素决定了后续元素的准则。
<?php use Abacus11\Doctrine\Collections\CollectionOf; $int_array = new CollectionOf([1, 2]); // Okay $int_array = new CollectionOf([1, '2']); // Not okay - throws \TypeError $int_array = new CollectionOf([null, 1]); // Not okay - throws \InvalidArgumentException
通过样本值定义类型
元素验证是针对样本值的类型进行的。
<?php use Abacus11\Doctrine\Collections\CollectionOf; $sample = 1; $int_array = (new CollectionOf())->setElementTypeLike($sample); $int_array[] = 2; // Okay $int_array[] = true; // Not okay - throws \TypeError exception class SomeClass {} $sample = new SomeClass(); $some = (new CollectionOf())->setElementTypeLike($sample); $some[] = new SomeClass(); // Okay $some[] = new stdClass(); // Not okay - throws \TypeError exception
通过闭包定义类型
可以通过闭包检查添加到集合中的元素。
<?php use Abacus11\Doctrine\Collections\CollectionOf; // Use the setElementType() method $positive_int = (new CollectionOf())->setElementType(function ($value) { if (!is_integer($value)) { return false; } return ($value >= 0); }); $positive_int['apples'] = 0; // Okay $positive_int['oranges'] = 10; // Okay $positive_int['bananas'] = -5; // Not okay - throws \TypeError exception // Or directly in the constructor $negative_int = new CollectionOf( function ($value) { if (!is_integer($value)) { return false; } return ($value <= 0); } ); $negative_int[] = -50; // Okay $negative_int[] = 5; // Not okay - throws \TypeError exception
通过类名定义类型
添加到集合中的对象可以与类名进行校验。
<?php use Abacus11\Doctrine\Collections\CollectionOf; class A {} class B {} class AA extends A {} // Use the setElementType() method $some_a = (new CollectionOf())->setElementType(A::class); $some_a[] = new A(); // Okay $some_a[] = new AA(); // Okay $some_a[] = new B(); // Not okay - throws \TypeError exception // Or directly in the constructor $some_b = new CollectionOf(B::class); $some_b[] = new B(); // Okay $some_b[] = new A(); // Not okay - throws \TypeError exception
内置库类型
除了闭包或类名之外,setElementType()
方法还接受以下值
数组
布尔值
可调用
双精度浮点数
整数
数字
JSON
对象
资源
字符串
<?php use Abacus11\Doctrine\Collections\CollectionOf; // Use the setElementType() method $int_array = (new CollectionOf())->setElementType('integer'); $int_array[] = 1; // Okay $int_array[] = '1'; // Not okay - throws \TypeError exception // Or directly in the constructor $int_array = new CollectionOf('integer'); $int_array[] = 20; // Okay $int_array[] = true; // Not okay - throws \TypeError exception
内置集合
预定义了几个类型化的集合
\Abacus11\Doctrine\Collections\Arrays
\Abacus11\Doctrine\Collections\Booleans
\Abacus11\Doctrine\Collections\Callables
\Abacus11\Doctrine\Collections\Doubles
\Abacus11\Doctrine\Collections\Integers
\Abacus11\Doctrine\Collections\Numbers
\Abacus11\Doctrine\Collections\JSONs
\Abacus11\Doctrine\Collections\Objects
\Abacus11\Doctrine\Collections\Resources
\Abacus11\Doctrine\Collections\Strings
<?php $integers = new \Abacus11\Doctrine\Collections\Integers([1, 2, 3, 0, -1]);
自定义类型集合
您可以通过扩展基本类或将特质包含到您自己实现的 ArrayAccess 接口中来轻松创建集合。
<?php use Abacus11\Doctrine\Collections\CollectionOf; class Vehicle { } class Car extends Vehicle { public $make; public $model; public $color; public $license_plate_number; } class Submarine extends Vehicle { public $name; } class Cars extends CollectionOf { /** * @param Car[] $cars */ public function __construct(array $cars = []) { parent::__construct(Car::class, $cars); // - or - //$this->setElementType(Car::class); //parent::__construct($cars); } } class Parking { /** * @var Cars */ protected $lot; public function __construct() { $this->lot = new Cars([]); } public function enter(Vehicle $car) { $this->lot[] = $car; } /** * @return Car[] The collection of cars */ public function getCars(): Cars { return $this->lot; } //... } $my_car = new Car(); $my_car->model = 'T'; $my_car->make = 'Ford'; $my_car->color = 'Black'; $my_car->license_plate_number = 'MI-01234'; $my_sub = new Submarine(); $my_sub->name = 'Nautilus'; $parking = new Parking(); $parking->enter($my_car); // Okay $parking->enter($my_sub); // Not okay - throws \TypeError exception
备注
- 我们本可以用
Car
类而不是Vehicle
类来提示enter()
方法。这也会抛出一个 \TypeError 异常。 - 我注意到我在 docBlock 和
getCars()
方法的签名中混合了类型。这可能会更容易阅读,并且可能有助于您的 IDE。然而,这种好处可能因编辑器/IDE 而异,并且如果尝试使用某些期望原生array
类型的数组函数,可能会导致混淆。