Skip to content

Commit 40c9a63

Browse files
committed
Initial commit
0 parents  commit 40c9a63

File tree

9 files changed

+329
-0
lines changed

9 files changed

+329
-0
lines changed

.scrutinizer.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
filter:
2+
excluded_paths: [tests/*]
3+
checks:
4+
php:
5+
code_rating: true
6+
remove_extra_empty_lines: true
7+
remove_php_closing_tag: true
8+
remove_trailing_whitespace: true
9+
fix_use_statements:
10+
remove_unused: true
11+
preserve_multiple: false
12+
preserve_blanklines: true
13+
order_alphabetically: true
14+
fix_php_opening_tag: true
15+
fix_linefeed: true
16+
fix_line_ending: true
17+
fix_identation_4spaces: true
18+
fix_doc_comments: true
19+
tools:
20+
php_analyzer: true
21+
php_code_coverage: false
22+
php_code_sniffer:
23+
config:
24+
standard: PSR2
25+
filter:
26+
paths: ['src']
27+
php_loc:
28+
enabled: true
29+
excluded_dirs: [vendor, tests]
30+
php_cpd:
31+
enabled: true
32+
excluded_dirs: [vendor, tests]

.travis.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
language: php
2+
3+
php:
4+
- 5.3
5+
- 5.4
6+
- 5.5
7+
- 5.6
8+
- 7.0
9+
- 7.1
10+
11+
before_script:
12+
- travis_retry composer self-update
13+
- travis_retry composer install --no-interaction --prefer-source --dev
14+
- travis_retry phpenv rehash
15+
16+
script:
17+
- ./vendor/bin/phpcs --standard=psr2 src/
18+
- mkdir -p build/logs
19+
- ./vendor/bin/phpunit --coverage-clover build/logs/clover.xml
20+
21+
after_script:
22+
- php vendor/bin/coveralls -v

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2017 Benoit POLASZEK
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

README.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
[![Latest Stable Version](https://poser.pugx.org/bentools/iterable-functions/v/stable)](https://packagist.org/packages/bentools/iterable-functions)
2+
[![License](https://poser.pugx.org/bentools/iterable-functions/license)](https://packagist.org/packages/bentools/iterable-functions)
3+
[![Build Status](https://img.shields.io/travis/bpolaszek/php-iterable-functions/master.svg?style=flat-square)](https://travis-ci.org/bpolaszek/php-iterable-functions)
4+
[![Coverage Status](https://coveralls.io/repos/github/bpolaszek/php-iterable-functions/badge.svg?branch=master)](https://coveralls.io/github/bpolaszek/php-iterable-functions?branch=master)
5+
[![Quality Score](https://img.shields.io/scrutinizer/g/bpolaszek/php-iterable-functions.svg?style=flat-square)](https://scrutinizer-ci.com/g/bpolaszek/php-iterable-functions)
6+
[![Total Downloads](https://poser.pugx.org/bentools/iterable-functions/downloads)](https://packagist.org/packages/bentools/iterable-functions)
7+
8+
Iterable functions
9+
==================
10+
11+
Provides additional functions to work with [iterable](https://wiki.php.net/rfc/iterable) variables (even on PHP5.3+).
12+
13+
is_iterable
14+
-----------
15+
To check wether or not a PHP variable can be looped over in a `foreach` statement, PHP provides an `is_iterable()` function.
16+
17+
**But this function only works on PHP7.1+**.
18+
19+
This library ships a portage of this function for previous PHP versions.
20+
21+
Usage:
22+
```php
23+
var_dump(is_iterable(array('foo', 'bar'))); // true
24+
var_dump(is_iterable(new DirectoryIterator(__DIR__))); // true
25+
var_dump(is_iterable('foobar')); // false
26+
```
27+
28+
iterable_to_array
29+
-----------------
30+
31+
PHP offers an `iterator_to_array()` function to export any iterator into an array.
32+
33+
**But when you want to transform an `iterable` to an array, the `iterable` itself can already be an array.**
34+
35+
When using `iterator_to_array()` with an array, PHP5 triggers a E_RECOVERABLE_ERROR while PHP7 throws a `TypeError`.
36+
37+
If you need an iterable-agnostic function, try our `iterable_to_array()`:
38+
39+
```php
40+
var_dump(iterable_to_array(new ArrayIterator(array('foo', 'bar')))); // ['foo', 'bar']
41+
var_dump(iterable_to_array(array('foo', 'bar'))); // ['foo', 'bar']
42+
```
43+
44+
Installation
45+
============
46+
47+
With composer (they'll be autoloaded):
48+
```
49+
composer require bentools/iterable-functions
50+
```
51+
52+
Or manually:
53+
```php
54+
require_once '/path/to/this/library/src/iterable-functions.php';
55+
```
56+
57+
Unit tests
58+
==========
59+
```
60+
./vendor/bin/phpunit
61+
```

composer.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "bentools/iterable-functions",
3+
"description": "Provides functions for iterable variables: is_iterable(), iterable_to_array()",
4+
"type": "library",
5+
"license": "MIT",
6+
"autoload": {
7+
"files": ["src/iterable-functions.php"]
8+
},
9+
"require": {
10+
"php": ">=5.3"
11+
},
12+
"require-dev": {
13+
"phpunit/phpunit": "@stable"
14+
}
15+
}

phpunit.xml.dist

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit backupGlobals="false"
3+
backupStaticAttributes="false"
4+
beStrictAboutTestsThatDoNotTestAnything="true"
5+
beStrictAboutOutputDuringTests="true"
6+
bootstrap="vendor/autoload.php"
7+
colors="true"
8+
convertErrorsToExceptions="true"
9+
convertNoticesToExceptions="true"
10+
convertWarningsToExceptions="true"
11+
failOnRisky="true"
12+
failOnWarning="true"
13+
processIsolation="false"
14+
stopOnError="false"
15+
stopOnFailure="false"
16+
verbose="true"
17+
>
18+
<testsuites>
19+
<testsuite name="Test Suite">
20+
<file>tests/TestIsIterable.php</file>
21+
<file>tests/TestIterableToArray.php</file>
22+
</testsuite>
23+
</testsuites>
24+
<filter>
25+
<whitelist processUncoveredFilesFromWhitelist="true">
26+
<directory suffix=".php">./src</directory>
27+
</whitelist>
28+
</filter>
29+
</phpunit>

src/iterable-functions.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
if (!function_exists('is_iterable')) {
4+
5+
/**
6+
* Check wether or not a variable is iterable (i.e array or \Traversable)
7+
* @param array|\Traversable $iterable
8+
* @return bool
9+
*/
10+
function is_iterable($iterable)
11+
{
12+
return is_array($iterable) || $iterable instanceof \Traversable;
13+
}
14+
}
15+
16+
if (!function_exists('iterable_to_array')) {
17+
18+
/**
19+
* Copy the iterable into an array. If the iterable is already an array, return it.
20+
* @param array|\Traversable $iterable
21+
* @return array
22+
*/
23+
function iterable_to_array($iterable)
24+
{
25+
return is_array($iterable) ? $iterable : iterator_to_array($iterable);
26+
}
27+
}

tests/TestIsIterable.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
use PHPUnit\Framework\TestCase;
4+
5+
class TestIsIterable extends TestCase
6+
{
7+
8+
public function testFunctionExists()
9+
{
10+
$this->assertTrue(function_exists('is_iterable'));
11+
}
12+
13+
public function testArrayIsIterable()
14+
{
15+
$array = array('foo', 'bar');
16+
$this->assertTrue(is_iterable($array));
17+
}
18+
19+
public function testIteratorIsIterable()
20+
{
21+
$iterator = new DirectoryIterator(__DIR__);
22+
$this->assertTrue(is_iterable($iterator));
23+
}
24+
25+
public function testScalarIsNotIterable()
26+
{
27+
$scalar = 'foobar';
28+
$this->assertFalse(is_iterable($scalar));
29+
}
30+
31+
public function testObjectIsNotIterable()
32+
{
33+
$object = new \stdClass();
34+
$this->assertFalse(is_iterable($object));
35+
}
36+
37+
public function testResourceIsNotIterable()
38+
{
39+
$resource = fopen('php://temp', 'rb');
40+
$this->assertFalse(is_iterable($resource));
41+
}
42+
43+
}

tests/TestIterableToArray.php

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php
2+
3+
use PHPUnit\Framework\TestCase;
4+
5+
class TestIterableToArray extends TestCase
6+
{
7+
8+
public function testFunctionExists()
9+
{
10+
$this->assertTrue(function_exists('iterable_to_array'));
11+
}
12+
13+
public function testIteratorToArray()
14+
{
15+
$iterator = new ArrayIterator(array('foo', 'bar'));
16+
$this->assertEquals(array('foo', 'bar'), iterable_to_array($iterator));
17+
}
18+
19+
public function testArrayToArray()
20+
{
21+
$array = array('foo', 'bar');
22+
$this->assertEquals(array('foo', 'bar'), iterable_to_array($array));
23+
}
24+
25+
public function testScalarToArray()
26+
{
27+
$scalar = 'foobar';
28+
$this->assertTrue($this->triggersError($scalar));
29+
}
30+
31+
public function testObjectToArray()
32+
{
33+
$object = new stdClass();
34+
$this->assertTrue($this->triggersError($object));
35+
}
36+
37+
public function testResourceToArray()
38+
{
39+
$resource = fopen('php://temp', 'rb');
40+
$this->assertTrue($this->triggersError($resource));
41+
}
42+
43+
private function triggersError($input)
44+
{
45+
return version_compare(PHP_VERSION, '7.0.0') >= 0 ? $this->triggersErrorPHP7($input) : $this->triggersErrorPHP5($input);
46+
}
47+
48+
private function triggersErrorPHP7($input)
49+
{
50+
$errorOccured = false;
51+
52+
try {
53+
iterable_to_array($input);
54+
}
55+
catch (\TypeError $e) {
56+
$errorOccured = true;
57+
}
58+
59+
return $errorOccured;
60+
}
61+
62+
private function triggersErrorPHP5($input)
63+
{
64+
$errorOccured = false;
65+
66+
set_error_handler(function ($errno) {
67+
return E_RECOVERABLE_ERROR === $errno;
68+
});
69+
70+
if (false === @iterable_to_array($input)) {
71+
$errorOccured = true;
72+
}
73+
74+
restore_error_handler();
75+
76+
return $errorOccured;
77+
}
78+
79+
}

0 commit comments

Comments
 (0)