Skip to content

Commit 81fa457

Browse files
author
Alaa Sarhan
committed
initial commit
0 parents  commit 81fa457

File tree

5 files changed

+208
-0
lines changed

5 files changed

+208
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/vendor/
2+
composer.lock

composer.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "sarhan/php-flatten",
3+
"description": "Flattens multidimensional arrays into one dimensional array.",
4+
"type": "library",
5+
"keywords": ["array", "flatten", "arrays"],
6+
"homepage": "https://github.com/AlaaSarhan/php-flatten",
7+
"license": "LGPL-3.0",
8+
"authors": [
9+
{
10+
"name": "Alaa Sarhan",
11+
"email": "sarhan.alaa@gmail.com"
12+
}
13+
],
14+
"autoload": {
15+
"psr-4": {
16+
"Sarhan\\": "./src/"
17+
}
18+
},
19+
"minimum-stability": "stable",
20+
"require": {
21+
"php": ">=5.5"
22+
},
23+
"require-dev": {
24+
"phpunit/phpunit": "^5.5"
25+
},
26+
"scripts": {
27+
"test": "phpunit"
28+
}
29+
}

phpunit.xml.dist

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<phpunit bootstrap="./vendor/autoload.php">
3+
4+
<testsuites>
5+
<testsuite name="Flatten">
6+
<directory>./test</directory>
7+
</testsuite>
8+
</testsuites>
9+
10+
</phpunit>

src/Flatten.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
namespace Sarhan;
3+
4+
class Flatten
5+
{
6+
public static function flatten($var, $separator = '.', $prefix = '')
7+
{
8+
if (!self::canTraverse($var)) {
9+
return $var;
10+
}
11+
12+
$flattened = [];
13+
foreach (self::flattenGenerator($var, $separator, $prefix) as $key => $value) {
14+
$flattened[$key] = $value;
15+
}
16+
return $flattened;
17+
}
18+
19+
private static function flattenGenerator($var, $separator, $prefix = '')
20+
{
21+
if (self::canTraverse($var)) {
22+
$prefix .= (empty($prefix) ? '' : $separator);
23+
foreach ($var as $key => $value) {
24+
foreach (self::flattenGenerator($value, $separator, $prefix . $key) as $k => $v) {
25+
yield $k => $v;
26+
}
27+
}
28+
} else {
29+
yield $prefix => $var;
30+
}
31+
}
32+
33+
private static function canTraverse($var)
34+
{
35+
return is_array($var) || ($var instanceof \Traversable);
36+
}
37+
}

test/FlattenTest.php

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<?php
2+
3+
use PHPUnit\Framework\TestCase;
4+
use Sarhan\Flatten;
5+
6+
class FlattenTest extends TestCase
7+
{
8+
public function scalarProvider()
9+
{
10+
return [
11+
[ null, null ],
12+
[ '', '' ],
13+
[ 0, 0 ],
14+
[ 3.14, 3.14 ],
15+
[ 'test', 'test' ],
16+
[ false, false ]
17+
];
18+
}
19+
20+
/**
21+
* @covers Flatten::flatten
22+
* @dataProvider scalarProvider
23+
*/
24+
public function testFlattenScalar($input, $expectedOutput)
25+
{
26+
$output = Flatten::flatten($input);
27+
28+
$this->assertEquals($expectedOutput, $output);
29+
}
30+
31+
public function arraysProvider()
32+
{
33+
return [
34+
[ [ ], [ ] ],
35+
[ [ 0 ], [ '0' => 0 ] ],
36+
[ [ 1, 2 ], [ '0' => 1, '1' => 2 ] ],
37+
[
38+
[ 1, 2, [ 3, 4 ] ],
39+
[ '0' => 1, '1' => 2, '2.0' => 3, '2.1' => 4 ]
40+
],
41+
[
42+
[ 'a' => 1, 2, 'b' => [ 3, 'c' => 4 ] ],
43+
[ 'a' => 1, '0' => 2, 'b.0' => 3, 'b.c' => 4 ]
44+
],
45+
[
46+
[ 'a' => 1, 'b' => 2, 'c' => [ 'd' => [ 3, 4 ], 'e' => [ 'f' => 5, 'g' => 6 ] ] ],
47+
[ 'a' => 1, 'b' => 2, 'c.d.0' => 3, 'c.d.1' => 4, 'c.e.f' => 5, 'c.e.g' => 6 ]
48+
]
49+
];
50+
}
51+
52+
/**
53+
* @covers Flatten::flatten
54+
* @dataProvider arraysProvider
55+
*/
56+
public function testFlattenArrays($input, $expectedOutput)
57+
{
58+
$output = Flatten::flatten($input);
59+
60+
$this->assertEquals($expectedOutput, $output);
61+
}
62+
63+
public function traversablesProvider()
64+
{
65+
return [
66+
[ new \ArrayIterator([ ]), [ ] ],
67+
[ new \ArrayIterator([ 0 ]), [ '0' => 0 ] ],
68+
[ new \ArrayIterator([ 1, 2 ]), [ '0' => 1, '1' => 2 ] ],
69+
[
70+
new \ArrayIterator([ 1, 2, [ 3, 4 ] ]),
71+
[ '0' => 1, '1' => 2, '2.0' => 3, '2.1' => 4 ]
72+
],
73+
[
74+
new \ArrayIterator([ 'a' => 1, 2, 'b' => new \ArrayIterator([ 3, 'c' => 4 ]) ]),
75+
[ 'a' => 1, '0' => 2, 'b.0' => 3, 'b.c' => 4 ]
76+
],
77+
[
78+
new \ArrayIterator([ 'a' => 1, 'b' => 2, 'c' => [ 'd' => [ 3, 4 ], 'e' => new \ArrayIterator([ 'f' => 5, 'g' => 6 ]) ] ]),
79+
[ 'a' => 1, 'b' => 2, 'c.d.0' => 3, 'c.d.1' => 4, 'c.e.f' => 5, 'c.e.g' => 6 ]
80+
]
81+
];
82+
}
83+
84+
/**
85+
* @covers Flatten::flatten
86+
* @dataProvider traversablesProvider
87+
*/
88+
public function testFlattenTraversable($input, $expectedOutput)
89+
{
90+
$output = Flatten::flatten($input);
91+
$this->assertEquals($expectedOutput, $output);
92+
}
93+
94+
public function traversablesSeparatorPrefixProvider()
95+
{
96+
return [
97+
[ new \ArrayIterator([ ]), '-', 'global', [ ] ],
98+
[ new \ArrayIterator([ 0 ]), '-', 'global', [ 'global-0' => 0 ] ],
99+
[ new \ArrayIterator([ 1, 2 ]), '-', 'global', [ 'global-0' => 1, 'global-1' => 2 ] ],
100+
[
101+
new \ArrayIterator([ 1, 2, [ 3, 4 ] ]),
102+
'-',
103+
'global',
104+
[ 'global-0' => 1, 'global-1' => 2, 'global-2-0' => 3, 'global-2-1' => 4 ]
105+
],
106+
[
107+
new \ArrayIterator([ 'a' => 1, 2, 'b' => new \ArrayIterator([ 3, 'c' => 4 ]) ]),
108+
'/',
109+
'local',
110+
[ 'local/a' => 1, 'local/0' => 2, 'local/b/0' => 3, 'local/b/c' => 4 ]
111+
],
112+
[
113+
new \ArrayIterator([ 'a' => 1, 'b' => 2, 'c' => [ 'd' => [ 3, 4 ], 'e' => new \ArrayIterator([ 'f' => 5, 'g' => 6 ]) ] ]),
114+
'',
115+
':',
116+
[ ':a' => 1, ':b' => 2, ':cd0' => 3, ':cd1' => 4, ':cef' => 5, ':ceg' => 6 ]
117+
]
118+
];
119+
}
120+
121+
/**
122+
* @covers Flatten::flatten
123+
* @dataProvider traversablesSeparatorPrefixProvider
124+
*/
125+
public function testFlattenTraversableWithSeparatorAndPrefix($var, $separator, $prefix, $expectedOutput)
126+
{
127+
$output = Flatten::flatten($var, $separator, $prefix);
128+
$this->assertEquals($expectedOutput, $output);
129+
}
130+
}

0 commit comments

Comments
 (0)