Build Quality Coverage Release License

PINQ

PHP Integrated query

View project onGitHub

PINQ V3.0.0

A lot of work has gone into improving PINQ for V3.0.0. Both the external API and internal implementation has been much improved. See below for the list of changes from the previous version. To view the full list of changes click here.

Improvements to the API

  • Query methods that take user supplied functions as parameters, now pass each element's associated key as the second parameter:

    • $strings->select(function ($string, $key) { return $key . $string; });
    • We have still maintained compatibility with single parameter internal functions like strlen.
    • Functions that take two parameters like str_split will behave differently as previously the second parameter would have been omitted. To fix this simply wrap functions like these in a closure as such:
      //This will no longer work as expected
      $strings->selectMany('str_split');
      //Use this instead
      $strings->selectMany(function ($string) { return str_split($string); });
  • Proper support for non scalar keys:

    • When using ITraversable::indexBy, you can now return any type of value and this will be handled correctly. Note that duplicate indexes will be associated with the first value for that index.
    • When foreaching over a ITraversable or calling ITraversable::asArray, all non scalar keys will be mapped to integers to maintain compatability.
    • Added ITraversable::iterate method to iterate all values and unaltered keys over the supplied function.
    • Added ITraversable::keys to select the keys as the values
    • AddedITraversable::reindex to index the values by their 0-based position.
    • Added ITraversable::getTrueIterator to get the iterator for all values and unaltered keys. This should not be foreach'ed in <= PHP 5.5.0
  • Updated interfaces annotations with covariant return types. ITraversable, ICollection, IQueryable, IRepository should all return their respective types for each query method.

    • Because of this, the Traversable and Collection classes are now extendable, custom methods can be added and everything should work smoothly.
    • Removed ITraversable::asQueryable, ITraversable::asRepository.
  • Implemented new ITraversable source semantics:

    • A source ITraversable is the instance containing the original underlying elements.
    • Added ITraversable::isSource, returns whether the instance is the source ITraversable:
      $elements = Traversable::from(range(1, 100));
      $elements->isSource(); //true
      $someElements = $elements->where(function ($i) { return $i > 50; });
      $someElements->isSource(); //false
    • Added ITraversable::getSource, returns the source ITraversable or itself if it is the source.
    • Removed unnecessary caching in Traversable queries.
      • Traversable can be used with nondeterministic/mutable sources and query parameters.
      • Traversable classes can no longer be serialized when queried with closures.
      • Because of this combined with covariant return types, ICollection/IRepository has a new and improved mutable query API:
        $collection = Collection::from(range(1, 10));
        $collection
               ->where(function ($i) { return $i >= 5; })
               ->apply(function (&$i) { $i *= 10; });
        $collection->asArray();//[1, 2, 3, 4, 50, 60, 70, 80, 90, 100]
        ...
        $collection = Collection::from(range(1, 10));
        $collection
               ->where(function ($i) { return $i <= 5; })
               ->clear();//[6, 7, 8, 9, 10]
  • Improved join/groupJoin API

    • IJoiningOnTraversable::onEquality will not match nulls as equal like C#.
    • New ->join/groupJoin(...)->apply(...) query operation for ICollection/IRepository
    • Implemented optional default value for ITraversable::join/ITraversable::groupJoin:
      Traversable::from(range(1, 6))
              ->join(range(1, 20))
              ->on(function ($outer, $inner) { return $outer % 2 === 0 && $outer * 2 === $inner; })
              ->withDefault('<Odd>')
              ->to(function ($outer, $inner) {
                  return $outer . ':' . $inner;
              });
              //Will produce: ['1:<Odd>', '2:4', '3:<Odd>', '4:8', '5:<Odd>', '6:12']
  • ITraversable::groupBy implicitly indexes each group by the group key value returned from the supplied function:

    • $strings
              ->groupBy(function ($i) { return strlen($i); })
              ->select(function (ITraversable $strings, $length) {
                  return $length . ':' . $strings->implode(',');
              });
  • Removed IGroupedTraversable and hence IGroupedTraversable::andBy:

    • ITraversable::groupBy implicitly indexes each group by the group key.
    • You cannot use multiple grouping functions any more, instead use ITraversable::groupBy with an array instead:
      //No longer supported
      $strings->groupBy('strlen')->andBy(function ($i) { return $i[0]; });
      //Instead use the following
      $strings->groupBy(function ($i) { return [strlen($i), $i[0]]; });
  • Implemented static analysis for expression trees with

  • Misc changes

    • Removed ITraversable::exists in favour of ITraversable::isEmpty.
    • Traversable/Collection are now extendable.
    • Fixed issue with ITraversable::union not reindexing keys.
    • Fixed issue with Iterators\Common\Set not detecting null values.

Improvements to internals

  • Refactored iterator structure:
    • Abstracted iterator implementations under Iterators\IIteratorScheme. Traversable and Collection now use this abstraction as factory for the required iterators rather than hard coded classes.
    • Now supports generators for automatic performance improvement and reduced memory usage for >= PHP 5.5.0
    • Will fall back to iterators for <= PHP 5.5.0
      • Native iterators have also been improved with regards to performance.
  • Improved query representations (under Queries namespace)

    • New builder API (under Builders) to build query objects from expression trees. Queryable/Repository now only construct the query expression tree. These classes parse the expression tree into the equivalent query structure.
    • Query parameters are now externalized from the query object. Under a IParameterRegistry instance.
    • New common ISource interface for a another sequence inside a query: ->intersect(...), ->join(...)
    • Removed FunctionExpressionTree in favour of dedicated function types (under Queries\Functions namespace) for all types of functions in a query:

      • ElementProjection:
        ->select(function ($value, $key) { return ... })
      • ElementMutator:
        ->apply(function (&$value, $key) { ... })
      • ConnectorProjection:
        ->join(...)->to(function ($outerValue, $innerValue, $outerKey, $innerKey) { return ... })
      • ConnectorMutator:
        ->join(...)->apply(function (&$outerValue, $innerValue, $outerKey, $innerKey) { ... })
      • Aggregator:
        ->aggregate(function ($aggregate, $value) { return ... })
    • New ISourceInfo to store source information of a IQueryable.

    • Renamed Segments\Operation::getTraversable to getValues

    • Refactored Join query segments / operations.

    • Removed redundant ...Expression from getter methods on expressions.

    • New expression classes

  • Restructured and improved function parsing

    • Upgraded to nikic/php-parser v1.0.0 with compatibility with PHP 5.6 language features
    • New function reflection API
    • Correctly handle resolving magic constants (__DIR__...) and scopes (self::...).
    • Largely improved signature matching using all reflection data to resolve to the correct function. Functions now have to be defined on the same line with identical signatures to cause an ambiguity.
    • Fixed fully qualified namespace detection in AST parsing.
    • Updated namespace: Parsing\PHPParser to Parsing\PhpParser.
  • Implemented necessary interfaces for fluent query building under Interfaces namespace.

    • IOrdered*, IJoiningOn*, IJoiningTo* with respective covariant return types.
  • Refactored caching implementation:

    • Caching\Provider renamed to Caching\CacheProvider
    • Caching\IQueryCache now acts as a wrapper to Caching\ICacheAdapter.
    • Any type of value can be cached and retrieved through the cache adapter.
    • Implemented namespacing API.