Skip to content

Commit fb209f1

Browse files
committed
Added typed arrays.
1 parent 07cb012 commit fb209f1

File tree

7 files changed

+163
-9
lines changed

7 files changed

+163
-9
lines changed

README.md

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ Table of Contents
99
- [1. Simple signature](#simple-signature)
1010
- [2. Union types](#union-types)
1111
- [3. Intersection types](#intersection-types)
12-
- [4. Optional parameters](#optional-parameters)
12+
- [4. Typed arrays](#typed-arrays)
13+
- [5. Optional parameters](#optional-parameters)
1314

1415
<a name="General usage"></a>
1516

@@ -62,9 +63,25 @@ Sometimes you allow parameter to be not of one type, but of several types.
6263
var_dump($func('1')) // => bool(true)
6364
```
6465

66+
<a name="typed-arrays"></a>
67+
68+
### 4. Typed arrays:
69+
70+
You can restrict your parameter to be an array of elements of certain types.
71+
72+
```php
73+
$func = new OverloadedFunction([
74+
'integer[]' => function ($arr) { return 'integer'; },
75+
'integer|string[]' => function ($arr) { return 'mixed'; }
76+
]);
77+
78+
var_dump($func([1, 2, 3])) // => string(7) "integer"
79+
var_dump($func([1, 2, '3'])) // => string(5) "mixed"
80+
```
81+
6582
<a name="optional-parameters"></a>
6683

67-
### 4. Optional parameters:
84+
### 5. Optional parameters:
6885

6986
Sometimes you allow parameter to be optional. Make sure you provide default values for such cases.
7087

src/Signature/Signature.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Sevavietl\OverloadedFunction\Signature\Types\Type;
66
use Sevavietl\OverloadedFunction\Signature\Types\UnionType;
77
use Sevavietl\OverloadedFunction\Signature\Types\IntersectionType;
8+
use Sevavietl\OverloadedFunction\Signature\Types\ArrayType;
89
use Sevavietl\OverloadedFunction\Signature\Types\OptionalType;
910

1011
class Signature
@@ -27,6 +28,10 @@ private function parseStringRepresentation($stringRepresentation)
2728
if (($optional = $this->isOptional($paramType))) {
2829
$paramType = substr($paramType, 1);
2930
}
31+
32+
if ($array = $this->isArray($paramType)) {
33+
$paramType = substr($paramType, 0, -2);
34+
}
3035

3136
if ($this->isUnion($paramType)) {
3237
$type = new UnionType(explode(self::UNION_TYPE_SEPARATOR, $paramType));
@@ -36,6 +41,8 @@ private function parseStringRepresentation($stringRepresentation)
3641
$type = new Type($paramType);
3742
}
3843

44+
$type = $array ? new ArrayType($type) : $type;
45+
3946
return $optional ? new OptionalType($type) : $type;
4047
}, $paramTypes);
4148
}
@@ -45,6 +52,11 @@ private function isOptional($paramType)
4552
return strpos($paramType, '?') === 0;
4653
}
4754

55+
private function isArray($paramType)
56+
{
57+
return preg_match('/(?:\[\])$/', $paramType);
58+
}
59+
4860
private function isUnion($paramType)
4961
{
5062
return strpos($paramType, self::UNION_TYPE_SEPARATOR) !== false;

src/Signature/Types/ArrayType.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace Sevavietl\OverloadedFunction\Signature\Types;
4+
5+
class ArrayType implements IType
6+
{
7+
private $type;
8+
9+
public function __construct(IType $type)
10+
{
11+
$this->type = $type;
12+
}
13+
14+
public function match($param)
15+
{
16+
$type = gettype($param);
17+
18+
if ($type !== 'array') {
19+
return false;
20+
}
21+
22+
foreach ($param as $item) {
23+
if (! $this->type->match($item)) {
24+
return false;
25+
}
26+
}
27+
28+
return true;
29+
}
30+
}

tests/unit/OverloadedFunctionTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,36 @@ public function invokeDataProvider()
123123
[2],
124124
true
125125
],
126+
[
127+
[
128+
'integer[]' => function ($arr) { return 'integer'; },
129+
'integer|string[]' => function ($arr) { return 'mixed'; }
130+
],
131+
[[1, 2, 3]],
132+
'integer'
133+
],
134+
[
135+
[
136+
'integer[]' => function ($arr) { return 'integer'; },
137+
'integer|string[]' => function ($arr) { return 'mixed'; }
138+
],
139+
[[1, 2, '3']],
140+
'mixed'
141+
],
142+
[
143+
[
144+
'string,?integer[]' => function ($a, $arr) { return true; },
145+
],
146+
['foo', [1, 2]],
147+
true
148+
],
149+
[
150+
[
151+
'string,?integer[]' => function ($a, $arr = []) { return true; },
152+
],
153+
['foo'],
154+
true
155+
],
126156
];
127157
}
128158

tests/unit/Signature/SignatureTest.php

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,15 @@
44

55
use Sevavietl\OverloadedFunction\Signature\Signature;
66
use Sevavietl\OverloadedFunction\Signature\Types\Type;
7-
use Sevavietl\OverloadedFunction\Signature\Types\DisjoinedType;
8-
use Sevavietl\OverloadedFunction\Signature\Types\ConjoinedType;
7+
use Sevavietl\OverloadedFunction\Signature\Types\ArrayType;
98
use Sevavietl\OverloadedFunction\Signature\Types\OptionalType;
109

1110
class SignatureTest extends \TestCase
1211
{
1312
public function testParseStringRepresentation()
1413
{
1514
// Arrange
16-
$stringRepresentation = 'string,integer,?boolean';
15+
$stringRepresentation = 'string,integer[],?boolean';
1716

1817
// Act
1918
$signature = new Signature($stringRepresentation);
@@ -28,8 +27,8 @@ public function testParseStringRepresentation()
2827
$this->assertInstanceOf(Type::class, $stringType);
2928
$this->assertAttributeEquals('string', 'typeString', $stringType);
3029

31-
$this->assertInstanceOf(Type::class, $integerType);
32-
$this->assertAttributeEquals('integer', 'typeString', $integerType);
30+
$this->assertInstanceOf(ArrayType::class, $integerType);
31+
$this->assertAttributeInstanceOf(Type::class, 'type', $integerType);
3332

3433
$this->assertInstanceOf(OptionalType::class, $booleanType);
3534
$this->assertAttributeInstanceOf(Type::class, 'type', $booleanType);
@@ -66,7 +65,11 @@ public function matchDataProvider()
6665
['string, integer, boolean', ['foo', 1], false],
6766
['string, integer, ?boolean', ['foo', 1], true],
6867
['NULL', [], true],
69-
['string, ArrayAccess, integer', ['foo', new \ArrayIterator, 1], true]
68+
['string, ArrayAccess, integer', ['foo', new \ArrayIterator, 1], true],
69+
['string[]', [['foo', 'bar']], true],
70+
['string[]', ['foo'], false],
71+
['string[]', [['1', '2', 3]], false],
72+
['string[]', [[1, 2, 3]], false],
7073
];
7174
}
7275
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
namespace Sevavietl\OverloadedFunction\Tests\Unit\Signature\Types;
4+
5+
use Sevavietl\OverloadedFunction\Signature\Types\Type;
6+
use Sevavietl\OverloadedFunction\Signature\Types\ArrayType;
7+
use Sevavietl\OverloadedFunction\Signature\Types\UnionType;
8+
use Sevavietl\OverloadedFunction\Signature\Types\IntersectionType;
9+
10+
class ArrayTypeTest extends \TestCase
11+
{
12+
/**
13+
* @dataProvider matchDataProvider
14+
*/
15+
public function testMatch($typeStrings, $param, $result)
16+
{
17+
$this->assertEquals($result, (new ArrayType($typeStrings))->match($param));
18+
}
19+
20+
public function matchDataProvider()
21+
{
22+
return [
23+
[new Type('string'), ['foo', 'bar'], true],
24+
[new Type('string'), ['foo', 1], false],
25+
[
26+
new UnionType(['ArrayAccess', 'Countable']),
27+
[new \ArrayIterator, new \ArrayIterator],
28+
true
29+
],
30+
[
31+
new UnionType(['ArrayAccess', 'Countable']),
32+
[new \ArrayObject, new \ArrayIterator],
33+
true
34+
],
35+
[
36+
new UnionType(['ArrayAccess', 'Countable']),
37+
[new \StdClass, new \ArrayIterator],
38+
false
39+
],
40+
[
41+
new UnionType(['stdClass', 'Countable']),
42+
[new \ArrayObject, new \ArrayIterator],
43+
true
44+
],
45+
[
46+
new UnionType(['stdClass', 'Countable']),
47+
[new \ArrayObject, new \StdClass],
48+
true
49+
],
50+
[
51+
new IntersectionType(['ArrayAccess', 'Countable']),
52+
[new \ArrayObject, new \ArrayIterator],
53+
true
54+
],
55+
[
56+
new IntersectionType(['ArrayAccess', 'Countable']),
57+
[new \ArrayObject, new \StdClass],
58+
false
59+
],
60+
];
61+
}
62+
}

tests/unit/Signature/Types/IntersectionTypeTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ public function matchDataProvider()
2121
[['Countable', 'RecursiveIterator'], new \ArrayIterator, false],
2222
];
2323
}
24-
}
24+
}

0 commit comments

Comments
 (0)