PHPackages                             jgswift/qinq - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Search &amp; Filtering](/categories/search)
4. /
5. jgswift/qinq

ActiveLibrary[Search &amp; Filtering](/categories/search)

jgswift/qinq
============

PHP 5.5+ quasi integrated query

0.1.5(11y ago)161142MITPHPPHP &gt;=5.5

Since Jun 24Pushed 11y ago1 watchersCompare

[ Source](https://github.com/jgswift/qinq)[ Packagist](https://packagist.org/packages/jgswift/qinq)[ RSS](/packages/jgswift-qinq/feed)WikiDiscussions master Synced today

READMEChangelog (5)Dependencies (6)Versions (6)Used By (2)

qinq
====

[](#qinq)

PHP 5.5+ quasi integrated query

[![Build Status](https://camo.githubusercontent.com/cb7ea5bec6d6f3d43aa36f4412333613af9f376f707e31fecb49a153900e480b/68747470733a2f2f7472617669732d63692e6f72672f6a6773776966742f71696e712e706e673f6272616e63683d6d6173746572)](https://travis-ci.org/jgswift/qinq)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/f938aa71b3a2ff0709d51f0610cb848f47e1f54bfa26ce7fb3524bdfdef26106/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f6a6773776966742f71696e712f6261646765732f7175616c6974792d73636f72652e706e673f733d34633134333363643436383634343065306138613265623261306433616163396432613632333337)](https://scrutinizer-ci.com/g/jgswift/qinq/)[![Latest Stable Version](https://camo.githubusercontent.com/2710dfeeb8b9d4747acd89497f74033a53b00ec6658cfd37b96a11b5b6e617f7/68747470733a2f2f706f7365722e707567782e6f72672f6a6773776966742f71696e712f762f737461626c652e737667)](https://packagist.org/packages/jgswift/qinq)[![License](https://camo.githubusercontent.com/ec9d4cc9d3cb1568502d4a9ad166833dafe50cffa3cd82a8d8befc9ba5bae91f/68747470733a2f2f706f7365722e707567782e6f72672f6a6773776966742f71696e712f6c6963656e73652e737667)](https://packagist.org/packages/jgswift/qinq)[![Coverage Status](https://camo.githubusercontent.com/980da718e9d23aa8da3091ca6b2b91a9c2b47fd62dfc8d16da8eb8898fdc633a/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f6a6773776966742f71696e712f62616467652e706e673f6272616e63683d6d6173746572)](https://coveralls.io/r/jgswift/qinq?branch=master)

Installation
------------

[](#installation)

Install via cli using [composer](https://getcomposer.org/):

```
php composer.phar require jgswift/qinq:0.1.*
```

Install via composer.json using [composer](https://getcomposer.org/):

```
{
    "require": {
        "jgswift/qinq": "0.1.*"
    }
}
```

Description
-----------

[](#description)

qinq is a lightweight array handling component that provides support for complex array manipulation with queries and built-in query caching

This package does not parse PHP or do any AST handling. qinq only manipulates arrays using php's built-in array functionality.

Dependency
----------

[](#dependency)

- php 5.5+
- [jgswift/qtil](http://github.com/jgswift/qtil) - general utility library
- [jgswift/kenum](http://github.com/jgswift/kenum) - enumerator implementation
- [jgswift/kfiltr](http://github.com/jgswift/kfiltr) - filter/map/hook implementation

Usage
-----

[](#usage)

The following is a basic example

```
$richPeople = $people
    ->where(function($person) { return $person['money'] > 1000000; })
    ->order(function($personA,$personB) { return ($personA['money'] < $personB['money']) ? -1 : 1; })
    ->index(function($person) { return $person['lastName']; })
    ->select(function($person) {
        return [
            'fullName' => $person['firstName'].' '.$person['lastName'],
            'money' => $person['money'],
            'networth' => $person['money'] - $person['debt']
        ];
    });
```

Populating a qinq collection

```
$integers = new qinq\Collection(range(1,50));
$names = new qinq\Collection(['bob','joe','sam','john','jake']);
```

### Filter

[](#filter)

```
// Retrieve all integers divisible by 5
foreach($integers->where(function($n) { return $n % 5 === 0; }) as $integer) {
    // 5, 10, 15, 20 ...
}

// Retrieve all names with a character length of 3
foreach($names->where(function($n) { return strlen($n) === 3; }) as $name) {
    // bob, joe, sam
}
```

### Map

[](#map)

Applies a callback to the collection elements

```
foreach($numbers
        ->filter(function($v) {
            return (bool)($v & 1); // filter out even values
        })
        ->map(function($v) {
            return $v * $v * $v; // cube all remaining odd values
        }) as $number) {
    // 1, 27, 125, 343, 729 ...
}
```

### Order

[](#order)

```
// Retrieves all integers in descending order
foreach($integers->order(qinq\Order::DESCENDING) as $integer) {
    // 50, 49, 48, 47 ...
}

// Retrieves all names in order of character length
foreach($names->order(function($n) { return strlen($n); } ) as $name ) {
    // john, jake, bob ...
}
```

### Sort

[](#sort)

```
// Retrieve all names in order of character length (with compare function)
foreach($names->sort(function($a,$b) { return (strlen($a) > strlen($b)) ? -1 : 1; } ) as $name ) {
    // john, jake, bob ...
}
```

### Group

[](#group)

```
// Group values by divisibility of 2
foreach($integers->group(function($n) { return $n % 2; }) as $group) {
    // [ 2, 4, 6, 8 ... ], [ 1, 3, 5, 7 ... ]
}

// Group names by to character length
foreach($names->group(function($n) { return strlen($n); }) as $group) {
    // [ bob, joe, sam ], [ john, jake ]
}
```

### Join

[](#join)

```
// Join integer collections using comparison method (on) and output method (to)
foreach($integers
    ->join($integers)
    ->on(function($outer,$inner) {
        return ($outer >= $inner) ? true : false;
    })
    ->to(function($outer,qinq\Collection $innerGroup) {
        return $outer.':'.implode(',',$innerGroup->toArray());
    }) as $integer ) {
        // 1:1 , 2:1,2 , 3:1,2,3 ...
    }

// Join integer and name collection, grouping names with integer that matches the character length
foreach($integers
    ->join($names)
    ->on(function($outer) {
        return $outer;
    }, 'strlen')
    ->to(function($outer,$inner) {
        return $outer.':'.$inner;
    }) as $number ) {
        // 3:bob, 3:joe, 3:sam, 4:john, 4:jake
    }
```

### Difference

[](#difference)

Computes the difference between collection and argument

```
foreach($integers
    ->difference(range(25,50))
    as $number) {
        // 1, 2, 3, ..., 24
    }
```

### Except

[](#except)

Alias of *Difference*

```
foreach($integers
    ->except(range(25,50))
    as $number) {
        // 1, 2, 3, ..., 24
    }
```

### First

[](#first)

Retrieves first item in collection.

```
echo $integers->first(); // 1
```

### Last

[](#last)

Retrieves last item in collection

```
echo $integers->last(); // 50
```

### Pluck

[](#pluck)

Aggregate specific array key or object property

```
$users = new qinq\Collection([
    [
        'name' => 'bob'
        'email' => 'bob@example.com'
    ],
    [
        'name' => 'jim'
        'email' => 'jim@example.com'
    ]
]);

foreach($users->pluck('name') as $name) {
    // bob, jim
}
```

```
class User {
    public $name, $email;

    function __construct($name, $email) { /* ... */ }
}

$users = new qinq\Collection([
    new User('bob','bob@example.com'),
    new User('jim','jim@example.com'),
]);

foreach($users->pluck('email') as $email) {
    // bob@example.com, jim@example.com
}
```

### From

[](#from)

Replaces entire collection with given arguments. A single array/Iterator/Collection may also be given.

```
foreach($integers
    ->from([3,4])
    as $number) {
        // 3, 4
    }
```

```
foreach($integers
    ->from(3,4,5)
    as $number) {
        // 3, 4, 5
    }
```

### Intersect

[](#intersect)

Retrieves values that exist in both arrays

```
foreach($integers
    ->intersect(range(25,100))
    as $number) {
        // 25, 26, 27, ..., 50
    }
```

### Reduce

[](#reduce)

Reduces array to single value using callback function

```
$q = new qinq\Collection([1,2,3,4,5]);

foreach($q
    ->reduce(function($carry,$item) {
        return $carry * $item; // 1 * 2 * 3 * 4 * 5
    })
    as $result) {
        // 120
    }
```

### Shuffle

[](#shuffle)

Mix all items in collection to new random positions

```
foreach($integers
    ->shuffle()
    as $result) {
        // random number between 1 and 50
    }
```

### Values

[](#values)

Retrieves all values from collection

```
foreach($integers
    ->values()
    as $result) {
        // 1, 2, 3, ..., 50
    }
```

### Keys

[](#keys)

Retrieves all collection keys

```
foreach($integers
    ->keys()
    as $number) {
        // 1, 2, 3, ..., 50
    }
```

### Pack

[](#pack)

Removes all data from collection that is weakly equivalent to false or 0

```
$junk = new qinq\Collection([
    false, 0, false, '0', 'hello'
]);

foreach($junk
    ->pack()
    as $item) {
        // 'hello'
    }
```

### Random

[](#random)

Selects a number of random items from collection

```
foreach($integers
    ->random(5)
    as $result) {
        // 5 random items from array
    }
```

### Recursive

[](#recursive)

Recursive maps through nested collections with a callback function

```
$numbers = new qinq\Collection([
    1, 2, [3, 4, [5, 6]], 7, [8, [9, 10]] // multidimensional array
]);

foreach($numbers
    ->recursive(function($value) {
        return $value * $value; // square(^2) values
    }) as $number) {
        // [ 1, 4, [ 9, 16, [ 25, 36 ] ] , 49, [ 64, [ 81, 100 ] ] ]
    }
```

### Search

[](#search)

Search filters through nested collections with a callback function

```
$numbers = new qinq\Collection([
    1, 2, [3, 4, [5, 6]], 7, [8, [9, 10]] // multidimensional array
]);

foreach($numbers
    ->search(function($value) {
        return ($value & 1) ? true : false; // only include odd values
    }) as $number) {
        // [ 1, [ 3, [ 5 ] ] , 7, [ 9 ] ]
    }
```

### Selector

[](#selector)

Selector filters through nested collections using common string selectors

```
$ages = new qinq\Collection([
    'joe' => 26,
    'jim' => 40
    'john' => 16
]);

foreach($ages
    ->selector('joe|jim') as $age) {
        // [ 26, 40 ]
    }

$favorites = new qinq\Collection([
    'joe' => [
        'color' => 'red',
        'hat' => 'fedora'
    ]
]);

foreach($favorites
    ->selector('[joe][color]') as $favorite) {
        // [ 'color' => 'red' ]
    }
```

### Flatten

[](#flatten)

Retrieves every value from a multidimensional collection tree and transforms it into a single dimensional collection

```
$tree = new qinq\Collection([
    [1,2,[8,9],3,4],
    [4,5,6,[1,2,3]],
    [8,[9,10],[4,5]]
]);

foreach($tree
    ->flatten()
    as $number) {
        // 1, 2, 8, 9, 3, 4, 4, 5..
    }
```

A flag argument may be provided to limit the flattening to certain types of collections or only arrays. The following example will leave the ArrayObject intact and avoid descending into any collections that are not strictly arrays.

```
use qinq\Object\Query\Flatten;

$tree = new qinq\Collection([
    [1,2,[3,4]
    [5,new ArrayObject([6,7,8])],
]);

foreach($tree
    ->flatten(Flatten::ARRAYONLY)
    as $number) {
        // 1, 2, 3, 4, ArrayObject()
    }
```

#### Flatten Flags

[](#flatten-flags)

- *Flatten::ARRAYONLY*

Flattens strictly php arrays, cancels all other flags

- *Flatten::COLLECTION*

Flattens objects implementing the qtil Traversable interface

- *Flatten::TRAVERSABLE*

Flattens objects implementing the built-in php Traversable interface.

- *Flatten::ITERATOR*

Flattens objects implementing the built-in php Iterator interface

*Note*: You may combine or exclude flags using [bitwise logic](http://php.net/manual/en/language.operators.bitwise.php).
The default flatten flag setting descends into any known collection type by default, namely COLLECTION, TRAVERSABLE, and ITERATOR.

### Storing

[](#storing)

qinq requires [jgswift/delegatr](http://github.com/jgswift/delegatr) to serialize and store queries.

```
$query = new \qinq\Object\Query($integers);

$query->select(function($n) {
    return $n * 3;
})->where(function($n) {
    return $n % 2 === 0;
});

$query_to_cache = serialize($query);

$query_from_cache = unserialize($query_to_cache);

var_dump( $query_from_cache->execute() === $query->execute() ) // true
```

*Note*: Query storing relies on *eval* to unserialize Closures.
Do not rely on users to provide serialized queries to your application as this can make your application vulnerable to code injection.
You can verify a queries authenticity by performing a cryptographic checksum on the serialized contents every time a client sends the query.
However said functionality is not implemented in this package.

###  Health Score

27

—

LowBetter than 49% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity17

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~44 days

Total

5

Last Release

4158d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/e60e96f18d8a9dc2aff1363eedbaf210acc96666e7497d2a83d5a416ef397295?d=identicon)[jgswift](/maintainers/jgswift)

---

Top Contributors

[![jgswift](https://avatars.githubusercontent.com/u/661738?v=4)](https://github.com/jgswift "jgswift (48 commits)")

---

Tags

phpquery

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/jgswift-qinq/health.svg)

```
[![Health](https://phpackages.com/badges/jgswift-qinq/health.svg)](https://phpackages.com/packages/jgswift-qinq)
```

###  Alternatives

[apicart/fql

Filter Query Language

1110.6k](/packages/apicart-fql)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
