boesing / typed-arrays
哈希表和集合
1.2.0
2024-01-25 16:08 UTC
Requires
- php: ~8.1.0 || ~8.2.0 || ~8.3.0
- webmozart/assert: ^1.9
Requires (Dev)
- doctrine/coding-standard: ^11.1
- phpunit/phpunit: ^9.6
- psalm/plugin-phpunit: ^0.18.4
- symfony/polyfill-php80: ^1.22
- vimeo/psalm: ^5.9
Conflicts
- vimeo/psalm: 4.6.2
- 2.0.x-dev
- 1.3.x-dev
- 1.2.x-dev
- 1.2.0
- 1.1.x-dev
- 1.1.0
- 1.0.x-dev
- 1.0.1
- 1.0.0
- 0.13.x-dev
- 0.13.1
- 0.13.0
- 0.12.x-dev
- 0.12.0
- 0.11.x-dev
- 0.11.2
- 0.11.1
- 0.11.0
- 0.10.x-dev
- 0.10.0
- 0.9.x-dev
- 0.9.2
- 0.9.1
- 0.9.0
- 0.8.x-dev
- 0.8.1
- 0.8.0
- 0.7.x-dev
- 0.7.0
- 0.6.x-dev
- 0.6.0
- 0.5.x-dev
- 0.5.0
- 0.4.x-dev
- 0.4.0
- 0.3.x-dev
- 0.3.0
- 0.2.x-dev
- 0.2.0
- 0.1.x-dev
- 0.1.0
- dev-feature/callable-purity
- dev-bugfix/invalid-return-type-count
- dev-qa/remove-unnecessary-internal
- dev-feature/map-has-key
- dev-qa/out-of-bounds-exception-in-favor-of-null
- dev-feature/find-in-list
- dev-codestandard
This package is auto-updated.
Last update: 2024-09-22 14:09:43 UTC
README
一个完全类型的库,用于处理列表或映射。
安装
要在项目中使用此库,请通过composer安装
$ composer require boesing/typed-arrays
用法
创建此库的主要原因在于PHP中的每个数组都是一个哈希表。如果您主要使用API,您可能已经体验过数组类型的json_encode
有时会导致令人烦恼的问题。
为了避免将数组传递通过应用程序,OrderedListInterface
和MapInterface
变得非常有用。为了向开发人员提供大多数array_*
函数,大多数这些数组函数在OrderedListInterface
或MapInterface
中都有方法。
常见错误
让我们通过一些真实世界的用例来更好地反映这个库背后的思想
$listOfIntegers = [1, 2, 3, 4]; $myObject = new stdClass(); $myObject->integers = $listOfIntegers; echo json_encode($myObject) . PHP_EOL; // Output of the code above will be: `{"integers":[1,2,3,4]}` // Now some refactoring has to be made since the requirement changed. The requirement now is that the integers list // must not contain odd values anymore. So `array_filter` to the rescue, right? $listOfEvenIntegers = array_filter([1, 2, 3, 4], static fn (int $integer): int => $integer % 2 === 0); $myObject = new stdClass(); $myObject->integers = $listOfEvenIntegers; echo json_encode($myObject) . PHP_EOL; // Output of the refactored code above now became: `{"integers":{"1":2,"3":4}}` // So what now happened is a huge problem for highly type-sensitive API clients since we changed a list to a hashmap // Same happens with hashmaps which suddenly become empty. $hashmap = [ 'foo' => 'bar', ]; $myObject = new stdClass(); $myObject->map = $hashmap; echo json_encode($myObject) . PHP_EOL; // Output of the code above will be: `{"map":{"foo":"bar"}}` // So now some properties are being added, some are being removed, the definition of your API says // "the object will contain additional properties because heck I do not want to declare every property" // "so to make it easier, every property has a string value" // can be easily done with something like this in JSONSchema: `{"type": "object", "additional_properties": {"type": "string"}}` // Now, some string value might become `null` due to whatever reason, lets say it was a bug and thus the happy path always returned a string // The most logical way here is, due to our lazyness, to use something like `array_filter` to get rid of all our non-string values $hashmap = [ 'foo' => null, ]; $myObject = new stdClass(); $myObject->map = array_filter($hashmap); echo json_encode($myObject) . PHP_EOL; // Output of the refactored code above now became: `{"map":[]}` // So in case that every array value is being wiped due to the filtering, we suddenly have a type-change from // a hashmap to a list. This is ofc also problematic since we do not want to have a list here but an empty object like // so: `{"map":{}}`
(上述示例可以在3v4l.org - 一个PHP沙盒上验证:https://3v4l.org/Gfogn#v8.1.6)
typed-arrays救星
所以,有了这个库,处理数组时可以稍微安全一些。然而,如果MapInterface
为空,它在json_encode
中实际上会变成null
。
所以让我们结合我们的工厂来使用上述示例
use Boesing\TypedArrays\TypedArrayFactory; $factory = new TypedArrayFactory(); $listOfIntegers = $factory->createOrderedList([1, 2, 3, 4]); $myObject = new stdClass(); $myObject->integers = $listOfIntegers; echo json_encode($myObject) . PHP_EOL; // Output of the code above will be: `{"integers":[1,2,3,4]}` // Now some refactoring has to be made since the requirement changed. The requirement now is that the integers list // must not contain odd values anymore. So `array_filter` to the rescue, right? $listOfEvenIntegers = $factory->createOrderedList([1, 2, 3, 4])->filter(static fn (int $integer): int => $integer % 2 === 0); $myObject = new stdClass(); $myObject->integers = $listOfEvenIntegers; echo json_encode($myObject) . PHP_EOL; // Output of the refactored code above now became: `{"integers":[2, 4]}` // Due to the internal handling of `array_filter`, the `OrderedListInterface` won't change its type. // Even hashmaps can be filtered, the type stays the same but in case of an empty map, `null` is being passed to the JSON object $hashmap = $factory->createMap([ 'foo' => 'bar', ]); $myObject = new stdClass(); $myObject->map = $hashmap; echo json_encode($myObject) . PHP_EOL; // Output of the code above will be: `{"map":{"foo":"bar"}}` // So now some properties are being added, some are being removed, the definition of your API says // "the object will contain additional properties because heck I do not want to declare every property" // "so to make it easier, every property has a string value" // can be easily done with something like this in JSONSchema: `{"type": "object", "additional_properties": {"type": "string"}}` // Now, some string value might become `null` due to whatever reason, lets say it was a bug and thus the happy path always returned a string // The most logical way here is, due to our lazyness, to use something like `array_filter` to get rid of all our non-string values $hashmap = $factory->createMap([ 'foo' => null, ]); $myObject = new stdClass(); $myObject->map = $hashmap->filter(static fn ($value) => $value !== null); echo json_encode($myObject) . PHP_EOL; // Output of the refactored code above now became: `{"map":null}` // So in case that every array value is being wiped due to the filtering, we suddenly have a type-change from // a hashmap to a list. This is ofc also problematic since we do not want to have a list here but an empty object like // so: `{"map":{}}`
结论
当涉及到API响应时,您可能不想依赖于PHP数组结构。始终优先选择具有真实属性和真实属性类型提示的真实对象,而不是non-empty-array
。