diff --git a/CHANGELOG.md b/CHANGELOG.md index 30d362d..a0419e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## 0.4.0 + +### Added + +- Type hinting for all functions. + +### Changed + +- PHP 8.0 is now the minimum required version. +- `phpunit^9.0` is now the minimum required version. +- Consolidated some redundant functions into one. + ## 0.3.1 ### Fixed @@ -17,7 +29,6 @@ - Removed (temporary) paysera/lib-php-cs-fixer-config ## 0.2.2 - ### Fixed - Saves originalData and introduces method `getOriginalData` to access it; Adds method `getDataAsArray` to get data in array form - remove clone @@ -25,21 +36,17 @@ - improve array handling in getObjectWrapperAsArray once more ## 0.2.1 - ### Fixed - improve array handling in getObjectWrapperAsArray ## 0.2.0 - ### Added - Ability to access originally passed data ## 0.1.1 - ### Fixed - Fixed mistype for exception message ## 0.1.0 - ### Fixed - Fixes strange test case with PHP 7.0 diff --git a/composer.json b/composer.json index 926bb00..7a0b1fc 100644 --- a/composer.json +++ b/composer.json @@ -7,10 +7,10 @@ } }, "require": { - "php": "^7.0 || ^8.0" + "php": ">=8.0" }, "require-dev": { - "phpunit/phpunit": "^6.0 || ^9.0" + "phpunit/phpunit": "^9.0|^10.0" }, "autoload-dev": { "psr-4": { diff --git a/src/ObjectWrapper.php b/src/ObjectWrapper.php index 920b611..d4592fc 100644 --- a/src/ObjectWrapper.php +++ b/src/ObjectWrapper.php @@ -1,4 +1,5 @@ path = $path; $this->data = clone $data; @@ -26,14 +27,14 @@ public function __construct(stdClass $data, $path = []) $this->processData(); } - private function processData() + private function processData(): void { foreach ($this->data as $key => &$item) { $item = $this->processItem($item, [$key]); } } - private function processItem($item, array $keys) + private function processItem(mixed $item, array $keys): mixed { if ($item instanceof stdClass) { return new self($item, array_merge($this->path, $keys)); @@ -44,7 +45,7 @@ private function processItem($item, array $keys) return $item; } - private function processArray(array $data, array $keys) + private function processArray(array $data, array $keys): array { foreach ($data as $i => &$item) { $item = $this->processItem($item, array_merge($keys, [(string)$i])); @@ -53,32 +54,38 @@ private function processArray(array $data, array $keys) return $data; } - public function offsetExists($key) + public function offsetExists(mixed $offset): bool { - return isset($this->data->$key); + return isset($this->data->$offset); } - public function offsetGet($key) + public function offsetGet(mixed $offset): mixed { - return isset($this->data->$key) ? $this->data->$key : null; + return $this->data->$offset ?? null; } - public function offsetSet($offset, $value) + public function offsetSet(mixed $offset, mixed $value): void { throw new RuntimeException('Modifying ObjectWrapper is not allowed'); } - public function offsetUnset($offset) + public function offsetUnset(mixed $offset): void { throw new RuntimeException('Modifying ObjectWrapper is not allowed'); } - public function getIterator() + public function getIterator(): ArrayIterator { return new ArrayIterator($this->data); } - public function getRequired(string $key) + /** + * @param string $key + * + * @return mixed + * @throws MissingItemException + */ + public function getRequired(string $key): mixed { if (!isset($this->data->$key)) { throw new MissingItemException($this->buildKey($key)); @@ -92,12 +99,7 @@ public function getRequiredBool(string $key): bool return $this->getRequiredOfType($key, 'boolean'); } - /** - * @param string $key - * @param bool|null $default - * @return bool|null - */ - public function getBool(string $key, bool $default = null) + public function getBool(string $key, ?bool $default = null): ?bool { return $this->getOfType($key, 'boolean', $default); } @@ -107,12 +109,7 @@ public function getRequiredFloat(string $key): float return $this->getRequiredOfType($key, 'float'); } - /** - * @param string $key - * @param float|null $default - * @return float|null - */ - public function getFloat(string $key, float $default = null) + public function getFloat(string $key, ?float $default = null): ?float { return $this->getOfType($key, 'float', $default); } @@ -122,26 +119,17 @@ public function getRequiredInt(string $key): int return $this->getRequiredOfType($key, 'integer'); } - /** - * @param string $key - * @param int|null $default - * @return int|null - */ - public function getInt(string $key, int $default = null) + public function getInt(string $key, ?int $default = null): ?int { return $this->getOfType($key, 'integer', $default); } - public function getRequiredObject(string $key): self + public function getRequiredObject(string $key): mixed { return $this->getRequiredOfType($key, 'object'); } - /** - * @param string $key - * @return ObjectWrapper|null - */ - public function getObject(string $key) + public function getObject(string $key): ?ObjectWrapper { return $this->getOfType($key, 'object', null); } @@ -151,12 +139,7 @@ public function getRequiredString(string $key): string return $this->getRequiredOfType($key, 'string'); } - /** - * @param string $key - * @param string|null $default - * @return string|null - */ - public function getString(string $key, string $default = null) + public function getString(string $key, ?string $default = null): ?string { return $this->getOfType($key, 'string', $default); } @@ -173,34 +156,15 @@ public function getOriginalData(): stdClass public function getDataAsArray(): array { - return $this->getObjectWrapperAsArray($this); - } - - private function getObjectWrapperAsArray(ObjectWrapper $objectWrapper) - { - $data = []; - foreach ($objectWrapper as $key => $item) { - if ($item instanceof ObjectWrapper) { - $data[$key] = $this->getObjectWrapperAsArray($item); - continue; - } elseif (is_array($item)) { - $data[$key] = $this->getObjectWrapperFromArray($item); - } else { - $data[$key] = $item; - } - } - - return $data; + return $this->recursiveToArray($this); } - private function getObjectWrapperFromArray(array $list) + private function recursiveToArray(ArrayAccess|array $inputData): array { $data = []; - foreach ($list as $key => $item) { - if ($item instanceof ObjectWrapper) { - $data[$key] = $this->getObjectWrapperAsArray($item); - } elseif (is_array($item)) { - $data[$key] = $this->getObjectWrapperFromArray($item); + foreach ($inputData as $key => $item) { + if ($item instanceof ArrayAccess || is_array($item)) { + $data[$key] = $this->recursiveToArray($item); } else { $data[$key] = $item; } @@ -209,14 +173,14 @@ private function getObjectWrapperFromArray(array $list) return $data; } - private function getRequiredOfType(string $key, string $expectedType) + private function getRequiredOfType(string $key, string $expectedType): mixed { $value = $this->getRequired($key); return $this->assertValueType($value, $expectedType, $key); } - private function getOfType(string $key, string $expectedType, $default) + private function getOfType(string $key, string $expectedType, $default): mixed { $value = $this[$key]; if ($value === null) { @@ -230,10 +194,11 @@ private function getOfType(string $key, string $expectedType, $default) * @param mixed $value * @param string $expectedType * @param string $key + * * @return mixed * @throws InvalidItemTypeException */ - private function assertValueType($value, string $expectedType, string $key) + private function assertValueType(mixed $value, string $expectedType, string $key): mixed { $givenType = gettype($value); if ($givenType === 'double') { @@ -289,7 +254,7 @@ public function getArrayOfObject(string $key): array return $this->getArrayOfType($key, 'object'); } - private function getArrayOfType(string $key, string $expectedType) + private function getArrayOfType(string $key, string $expectedType): array { $value = $this->getArray($key); @@ -298,7 +263,7 @@ private function getArrayOfType(string $key, string $expectedType) }, $value); } - private function buildKey(string $key) + private function buildKey(string $key): string { return implode('.', array_merge($this->path, [$key])); } diff --git a/tests/ObjectWrapperTest.php b/tests/ObjectWrapperTest.php index 63c2d52..f5f35dc 100644 --- a/tests/ObjectWrapperTest.php +++ b/tests/ObjectWrapperTest.php @@ -1,4 +1,5 @@ 'b', 'c' => ['d' => 'e']]); $this->assertTrue(isset($object['a'])); @@ -20,7 +21,7 @@ public function testOffsetExists() $this->assertFalse(isset($object['d'])); } - public function testOffsetGet() + public function testOffsetGet(): void { $object = new ObjectWrapper((object)['a' => 'b', 'c' => (object)['d' => 'e']]); $this->assertSame('b', $object['a']); @@ -29,27 +30,27 @@ public function testOffsetGet() $this->assertInstanceOf(ObjectWrapper::class, $object['c']); } - public function testOffsetSet() + public function testOffsetSet(): void { $this->expectException(RuntimeException::class); $object = new ObjectWrapper((object)['a' => 'b', 'c' => ['d' => 'e']]); $object['q'] = 'e'; } - public function testOffsetUnset() + public function testOffsetUnset(): void { $this->expectException(RuntimeException::class); $object = new ObjectWrapper((object)['a' => 'b', 'c' => ['d' => 'e']]); unset($object['q']); } - public function testGetIterator() + public function testGetIterator(): void { $object = new ObjectWrapper((object)['a' => 'b', 'c' => ['d' => 'e']]); $this->assertSame(['a' => 'b', 'c' => ['d' => 'e']], iterator_to_array($object)); } - public function testGetRequired() + public function testGetRequired(): void { $object = new ObjectWrapper((object)['a' => 'b']); $this->assertSame('b', $object->getRequired('a')); @@ -57,42 +58,42 @@ public function testGetRequired() $object->getRequired('c'); } - public function testGetRequiredBoolWithNoItem() + public function testGetRequiredBoolWithNoItem(): void { $object = new ObjectWrapper((object)[]); $this->expectException(MissingItemException::class); $object->getRequiredBool('a'); } - public function testGetRequiredFloatWithNoItem() + public function testGetRequiredFloatWithNoItem(): void { $object = new ObjectWrapper((object)[]); $this->expectException(MissingItemException::class); $object->getRequiredFloat('a'); } - public function testGetRequiredIntWithNoItem() + public function testGetRequiredIntWithNoItem(): void { $object = new ObjectWrapper((object)[]); $this->expectException(MissingItemException::class); $object->getRequiredInt('a'); } - public function testGetRequiredObjectWithNoItem() + public function testGetRequiredObjectWithNoItem(): void { $object = new ObjectWrapper((object)[]); $this->expectException(MissingItemException::class); $object->getRequiredObject('a'); } - public function testGetRequiredStringWithNoItem() + public function testGetRequiredStringWithNoItem(): void { $object = new ObjectWrapper((object)[]); $this->expectException(MissingItemException::class); $object->getRequiredString('a'); } - public function testGetRequiredBool() + public function testGetRequiredBool(): void { $object = new ObjectWrapper((object)['a' => true, 'b' => 'other type', 'c' => 'false', 'd' => '1', 'e' => 0]); $this->assertTrue($object->getRequiredBool('a')); @@ -103,16 +104,16 @@ public function testGetRequiredBool() $object->getRequiredBool('b'); } - public function testGetRequiredFloat() + public function testGetRequiredFloat(): void { $object = new ObjectWrapper((object)['a' => 1.23, 'b' => 1, 'c' => 'other type']); $this->assertSame(1.23, $object->getRequiredFloat('a')); - $this->assertSame((float)1, $object->getRequiredFloat('b')); + $this->assertSame(1.0, $object->getRequiredFloat('b')); $this->expectException(InvalidItemTypeException::class); $object->getRequiredFloat('c'); } - public function testGetRequiredInt() + public function testGetRequiredInt(): void { $object = new ObjectWrapper((object)['a' => 1, 'b' => 1.23]); $this->assertSame(1, $object->getRequiredInt('a')); @@ -120,7 +121,7 @@ public function testGetRequiredInt() $object->getRequiredInt('b'); } - public function testGetRequiredObject() + public function testGetRequiredObject(): void { $data = new stdClass(); $data->a = 'a'; @@ -130,7 +131,7 @@ public function testGetRequiredObject() $object->getRequiredObject('b'); } - public function testGetRequiredString() + public function testGetRequiredString(): void { $object = new ObjectWrapper((object)['a' => 'string', 'b' => 123]); $this->assertSame('string', $object->getRequiredString('a')); @@ -138,7 +139,7 @@ public function testGetRequiredString() $object->getRequiredString('b'); } - public function testGetBool() + public function testGetBool(): void { $object = new ObjectWrapper((object)['a' => true, 'b' => 'other type']); $this->assertTrue($object->getBool('a')); @@ -148,7 +149,7 @@ public function testGetBool() $object->getRequiredBool('b'); } - public function testGetFloat() + public function testGetFloat(): void { $object = new ObjectWrapper((object)['a' => 1.23, 'b' => 1, 'c' => 'other type']); $this->assertSame(1.23, $object->getFloat('a')); @@ -159,7 +160,7 @@ public function testGetFloat() $object->getFloat('c'); } - public function testGetInt() + public function testGetInt(): void { $object = new ObjectWrapper((object)['a' => 1, 'b' => 1.23]); $this->assertSame(1, $object->getInt('a')); @@ -169,7 +170,7 @@ public function testGetInt() $object->getInt('b'); } - public function testGetObject() + public function testGetObject(): void { $data = new stdClass(); $data->a = 'a'; @@ -180,7 +181,7 @@ public function testGetObject() $object->getObject('b'); } - public function testGetString() + public function testGetString(): void { $object = new ObjectWrapper((object)['a' => 'string', 'b' => 123]); $this->assertSame('string', $object->getString('a')); @@ -190,7 +191,7 @@ public function testGetString() $object->getString('b'); } - public function testGetArray() + public function testGetArray(): void { $array = [1, '2', 3.0, false, (object)['a' => 'b']]; $object = new ObjectWrapper((object)['a' => $array, 'empty' => []]); @@ -200,20 +201,20 @@ public function testGetArray() $this->assertSame([], $object->getArray('empty', [1, 2, 3])); } - public function testGetArrayWithDifferentType() + public function testGetArrayWithDifferentType(): void { $object = new ObjectWrapper((object)['a' => 'string']); $this->expectException(InvalidItemTypeException::class); $object->getArray('a'); } - public function testGetArrayWithNull() + public function testGetArrayWithNull(): void { $object = new ObjectWrapper((object)['a' => null]); $this->assertSame([], $object->getArray('a')); } - public function testGetArrayOfBool() + public function testGetArrayOfBool(): void { $array = [false, false, true]; $object = new ObjectWrapper((object)['a' => $array, 'empty' => []]); @@ -222,14 +223,14 @@ public function testGetArrayOfBool() $this->assertSame([], $object->getArrayOfBool('empty')); } - public function testGetArrayOfBoolWithDifferentType() + public function testGetArrayOfBoolWithDifferentType(): void { $object = new ObjectWrapper((object)['a' => 'string']); $this->expectException(InvalidItemTypeException::class); $object->getArrayOfBool('a'); } - public function testGetArrayOfBoolWithDifferentItemType() + public function testGetArrayOfBoolWithDifferentItemType(): void { $array = [false, 'false', 0, true, 1, 'true']; $object = new ObjectWrapper((object)['a' => $array]); @@ -239,7 +240,7 @@ public function testGetArrayOfBoolWithDifferentItemType() ); } - public function testGetArrayOfFloat() + public function testGetArrayOfFloat(): void { $array = [1, 1.0, 2.3]; $object = new ObjectWrapper((object)['a' => $array, 'empty' => []]); @@ -248,14 +249,14 @@ public function testGetArrayOfFloat() $this->assertSame([], $object->getArrayOfFloat('empty')); } - public function testGetArrayOfFloatWithDifferentType() + public function testGetArrayOfFloatWithDifferentType(): void { $object = new ObjectWrapper((object)['a' => 'string']); $this->expectException(InvalidItemTypeException::class); $object->getArrayOfFloat('a'); } - public function testGetArrayOfFloatWithDifferentItemType() + public function testGetArrayOfFloatWithDifferentItemType(): void { $array = [1.0, 2.3, false]; $object = new ObjectWrapper((object)['a' => $array]); @@ -263,7 +264,7 @@ public function testGetArrayOfFloatWithDifferentItemType() $object->getArrayOfFloat('a'); } - public function testGetArrayOfFloatWithNullItem() + public function testGetArrayOfFloatWithNullItem(): void { $array = [1.0, 2.0, null, 3.3]; $object = new ObjectWrapper((object)['a' => $array]); @@ -271,7 +272,7 @@ public function testGetArrayOfFloatWithNullItem() $object->getArrayOfFloat('a'); } - public function testGetArrayOfInt() + public function testGetArrayOfInt(): void { $array = [0, -10, 2211223]; $object = new ObjectWrapper((object)['a' => $array, 'empty' => []]); @@ -280,14 +281,14 @@ public function testGetArrayOfInt() $this->assertSame([], $object->getArrayOfInt('empty')); } - public function testGetArrayOfIntWithDifferentType() + public function testGetArrayOfIntWithDifferentType(): void { $object = new ObjectWrapper((object)['a' => 'string']); $this->expectException(InvalidItemTypeException::class); $object->getArrayOfInt('a'); } - public function testGetArrayOfIntWithDifferentItemType() + public function testGetArrayOfIntWithDifferentItemType(): void { $array = [1, 9, 2.1, 4]; $object = new ObjectWrapper((object)['a' => $array]); @@ -295,7 +296,7 @@ public function testGetArrayOfIntWithDifferentItemType() $object->getArrayOfInt('a'); } - public function testGetArrayOfIntWithNullItem() + public function testGetArrayOfIntWithNullItem(): void { $array = [1, 3, null, 5]; $object = new ObjectWrapper((object)['a' => $array]); @@ -303,7 +304,7 @@ public function testGetArrayOfIntWithNullItem() $object->getArrayOfInt('a'); } - public function testGetArrayOfString() + public function testGetArrayOfString(): void { $array = ['', '123123', 'string']; $object = new ObjectWrapper((object)['a' => $array, 'empty' => []]); @@ -312,14 +313,14 @@ public function testGetArrayOfString() $this->assertSame([], $object->getArrayOfString('empty')); } - public function testGetArrayOfStringWithDifferentType() + public function testGetArrayOfStringWithDifferentType(): void { $object = new ObjectWrapper((object)['a' => 1]); $this->expectException(InvalidItemTypeException::class); $object->getArrayOfString('a'); } - public function testGetArrayOfStringWithDifferentItemType() + public function testGetArrayOfStringWithDifferentItemType(): void { $array = ['string', 'aaa', 4]; $object = new ObjectWrapper((object)['a' => $array]); @@ -327,7 +328,7 @@ public function testGetArrayOfStringWithDifferentItemType() $object->getArrayOfString('a'); } - public function testGetArrayOfStringWithNullItem() + public function testGetArrayOfStringWithNullItem(): void { $array = ['string', 'item', null]; $object = new ObjectWrapper((object)['a' => $array]); @@ -335,7 +336,7 @@ public function testGetArrayOfStringWithNullItem() $object->getArrayOfString('a'); } - public function testGetArrayOfObject() + public function testGetArrayOfObject(): void { $structure = new stdClass(); $jsonStructure = json_decode('{"a":"b"}'); @@ -346,21 +347,21 @@ public function testGetArrayOfObject() $this->assertSame([], $object->getArrayOfObject('empty')); } - public function testGetArrayOfObjectWithDifferentType() + public function testGetArrayOfObjectWithDifferentType(): void { $object = new ObjectWrapper((object)['a' => 1]); $this->expectException(InvalidItemTypeException::class); $object->getArrayOfObject('a'); } - public function testGetArrayOfObjectWithDifferentItemType() + public function testGetArrayOfObjectWithDifferentItemType(): void { $object = new ObjectWrapper((object)['a' => 'string']); $this->expectException(InvalidItemTypeException::class); $object->getArrayOfObject('a'); } - public function testGetArrayOfObjectWithNullItem() + public function testGetArrayOfObjectWithNullItem(): void { $array = [(object)['a' => 'b'], (object)[0 => 0, 1 => 1], null]; $object = new ObjectWrapper((object)['a' => $array]); @@ -368,7 +369,7 @@ public function testGetArrayOfObjectWithNullItem() $object->getArrayOfObject('a'); } - public function testGetArrayOfObjectWithAssociativeArrayItem() + public function testGetArrayOfObjectWithAssociativeArrayItem(): void { $array = [(object)['a' => 'b'], (object)[0 => 0, 1 => 1], ['a' => 'b']]; $object = new ObjectWrapper((object)['a' => $array]); @@ -376,7 +377,7 @@ public function testGetArrayOfObjectWithAssociativeArrayItem() $object->getArrayOfObject('a'); } - public function testDoesNotAffectInput() + public function testDoesNotAffectInput(): void { $innerData = (object)['b' => 'c']; $data = new stdClass(); @@ -386,7 +387,7 @@ public function testDoesNotAffectInput() $this->assertSame($innerData, $data->a); } - public function testGetOriginalData() + public function testGetOriginalData(): void { $innerData = (object)['b' => 'c']; $data = new stdClass(); @@ -396,7 +397,7 @@ public function testGetOriginalData() $this->assertDeepEquals($data, $originalData); } - public function testGetOriginalDataAsArray() + public function testGetOriginalDataAsArray(): void { $innerData = (object)['b' => 'c']; $data = new stdClass(); @@ -425,12 +426,12 @@ public function testGetOriginalDataAsArray() $this->assertDeepEquals($expectedArray, $originalData); } - private function assertDeepEquals($expectedData, $dataWithWrappers) + private function assertDeepEquals($expectedData, $dataWithWrappers): void { $this->assertEquals($expectedData, $this->unwrap($dataWithWrappers)); } - private function unwrap($dataWithWrappers) + private function unwrap($dataWithWrappers): mixed { if ($dataWithWrappers instanceof ObjectWrapper) { $result = new stdClass();