It is a minimalist library that process arrays in PHP.

2.0 2024-03-10 22:49 UTC

This package is auto-updated.

Last update: 2024-04-10 23:10:10 UTC


It is a minimalist library that process arrays in PHP.

This library is focused to work with business data(reading/saving files, database records, API, etc.), so it is not similar to Numpy, Pandas, NumPHP or alike because they target difference objectives. It is more closely similar to Microsoft PowerQuery and Linq. What it does? Filter, order, renaming column, grouping, validating, amongst many other operations.

  • it works with PHP arrays. PHP arrays allows hierarchy structures using indexed and/or associative values.
  • It is aimed at speed.
  • It is minimalist, using the minimum of dependencies and only 1 PHP class. Do you hate when a simple library adds a whole framework as dependency? Well, not here.
  • It works using fluent/nested notations.
  • Every method is documented using PhpDoc.

Packagist Total Downloads Maintenance composer php php CocoaPods

Basic examples

// Reducing an array using aggregate functions:
    'date'=>new DateTime('now'),
    ->all(); //['unitPrice'=>800,'quanty'=>12]
// or also
$arr=(new ArrayOne($invoice['detail']))
    ->all(); //['unitPrice'=>800,'quanty'=>12]

Getting started

First, you must install the library. You can download this library or use Composer for its installation:

composer require eftec/arrayone

Once the library is installed and included, you can use as:

use eftec\ArrayOne;
ArrayOne::set($array); // Initial operator: $array is our initial array.
    ->someoperator1()  // Middle operator: here we do one or many operations to transform the array
    ->all(); // End operator: and we get the end result that usually is an array but it could be even a literal.


$array=['hello'  // indexed field
       'field2'=>'world', // named field
       'fields'=>[   // a field with sub-fields
       'table'=>[ // a field with a list of values (a table)
  • indexed and named fields works similarly.
  • Sometimes, some field contains an array of values that behave like a table (see table field)

initial operator

Initial operator is the first operator of the chain.


It sets the array to be transformed, and it starts the pipeline. It must be the first operator unless you are using the constructor.

ArrayOne::set($array,$object)->all(); // the object is used by validation()
ArrayOne::set($array,SomeClass:class)->all(); // the object is used by validation()
  • parameter array|null $array
  • parameter object|null|string $service the service instance. You can use the class or an object.


It sets the initial array readint the values from the request (get/post/header/etc.)

    'id'=>'get', // $_GET['id'] if not found then it uses the default value (null)
    'name'=>'post|default', // $_POST['name'], if not found then it uses "default"
    'content'=>'body' // it reads from the POST body
],null); // null is the default value if not other default value is set.
  • parameter array $fields An associative array when the values to read 'id'=>'type;defaultvalue'. Types:
    get: get it from the query string
    post: get it from the post
    header: get if from the header
    request: get if from the post, otherwise from get
    cookie: get if from the cookies
    body: get if from the post body (values are not serialized)
    verb: get if from the request method (GET/POST/PUT,etc.)
  • parameter mixed $defaultValueAll the default value if the value is not found and not other default value is set.
  • parameter ?string $separator Def:'.', The separator character used when the field is nested.
    example using '.' as separator html:
    result obtained:$result['a']['b']='hello';
  • return value ArrayOne


It sets the array using a json. Example:

  • parameter string $json the value to parse.


It sets the array using a csv. This csv must have a header.

  • parameter string $string the string to parse
  • parameter string $separator default ",". Set the field delimiter (one character only).
  • parameter string $enclosure default '"'. Set the field enclosure character (one character only).
  • parameter string $escape default "\". Set the escape character (one character only).


It sets the array using a head-less csv.

  • parameter string $string the string to parse
  • parameter array|null $header If the header is null, then it creates an indexed array.
    if the header is an array, then it is used as header
  • parameter string $separator default ",". Set the field delimiter (one character only).
  • parameter string $enclosure default '"'. Set the field enclosure character (one character only).
  • parameter string $escape default "\". Set the escape character (one character only).

middle operator

Middle operators are operators that are called between the initial operator set() and the end operator all() or getCurrent(). They do the transformation and they could be stacked.


    ->group('col1',['col2'=>'sum']) // middle operator #2


Returns a single column as an array of values.

$this->col('c1'); // [['c1'=>1,'c2'=>2],['c1'=>3,'c2'=>4]] => [['c1'=>1],['c1'=>3]];


it converts a column into an index

$this->indexToField('colold'); //  [['colold'=>'a','col1'=>'b','col2'=>'c'] => ['a'=>['col1'=>'b','col2'=>'c']]
  • parameter mixed $oldColumn the old column. This column will be converted into an index


It filters the values. If the condition is false, then the row is deleted. It uses array_filter()
The indexes are not rebuilt. Example:

$array = [['id' => 1, 'name' => 'chile'], ['id' => 2, 'name' => 'argentina'], ['id' => 3, 'name' => 'peru']];
// get the row #2 "argentina":
// using a function:
$r = ArrayOne::set($array)->filter(function($row, $id) {return $row['id'] === 2;}, true)->result();
// using a function a returning a flat result:
$r = ArrayOne::set($array)->filter(function($row, $id) {return $row['id'] === 2;}, false)->result();
// using an associative array:
$r = ArrayOne::set($array)->filter(['id'=>'eq;2'], false)->result();
// using an associative array that contains an array:
$r = ArrayOne::set($array)->filter(['id'=>['eq,2]], false)->result();
// multiples conditions: id=2 and col=10
$r = ArrayOne::set($array)->filter([['id'=>'eq;2'],['col','eq;10]], false)->result();

You can find an example in examplefindandfilter Note: see validate for more information about conditions.


It returns an array with the key and values of the elements that matches the condition.

  • parameter callable|null|array $condition you can use a callable function ($row,$id):bool {}
    or a comparison array ['id'=>'eq;2|lt;3'] "|" adds more comparisons
    or a comparison array [['id=>['eq',2]]],['id'=>['lt',3]]
  • parameter bool $onlyFirst if true then it only returns the first value
  • parameter string $mode =['all','key','value'] // (default is all)
    all returns the key and the value obtained
    key only returns the key
    value only returns the value


ArrayOne::set($array)->find(function($row, $id) {
          return $row['id'] === 2;
          })->all(); // [[0,"apple"],[3,"pear"]]

It uses the same conditions as filter()

isIndexArray() isIndex()

Returns true if the array is an indexed array. It does not scan the whole array, but instead it only returns true if the index 0 exists, and it is the first value.

ArrayOne::isIndexArray(['cocacola','fanta']); // true
ArrayOne::isIndexArray(['prod1'=>'cocacola','prod2'=>'fanta']); // false (associative array)
ArrayOne::isIndexArray('cocacola'); // false (not array)
ArrayOne::set(['cocacola','fanta'])->isIndex(); // dynamic method (true)

isIndexTableArray() isIndexTable()

It returns true if the value is an indexed array with the first value an array (i.e. a table) Example:

ArrayOne::isIndexTableArray([['cocacola','fanta']]); // true
ArrayOne::isIndexTableArray(['cocacola','fanta']); // false
ArrayOne::isIndexTableArray(['first'=>['hello'],'second'=>'world']) // false


It returns the first element of an array.

  • return value $this


It flats the results. If the result is an array with a single row, then it returns the row without the array

$this->flat(); // [['a'=>1,'b'=>2]] => ['a'=>1,'b'=>2]
  • return value $this


It groups one column and return its column grouped and values aggregated.

The grouped value is used as the new index key.


// group in the same column using a predefined function:
$this->group('type',['c1'=>'sum','price'=>'sum']); // ['type1'=>['c1'=>20,'price'=>30]]
// group in a different column using a predefined function:
// group using an indexed index:
$this->group('type',['c1'=>'sum','pri'=>'sum','grp'=>'group'],false); // [['c1'=>20,'pri'=>30,'grp'=>'type1']]
// group using a function:
$this->group('type',['c1'=>function($cumulate,$row) { return $cumulate+$row['c1'];}]);
// group using two functions, one per every row and the other at the end:
		  function($cumulate,$row) { return $cumulate+$row['c1'];},
		  function($cumulate,$numrows) { return $cumulate/$numRows;}]); // obtain the average of c1
  • parameter mixed $column the column to group.
  • parameter array $functionAggregation An associative array ['col-to-agregate'=>'aggregation']
    or ['new-col'=>'aggregation(col-to-agregate)']
    or ['col-to-aggr'=>function($cumulate,$row) {}]
    or ['col-to-aggr'=>[function($cumulate,$row){},function($cumulate,$numRows){}]
    stack: It stacks the rows grouped by the column (like a pivot table).
    count: Count
    avg: Average
    min: Minimum
    max: Maximum
    sum: Sum
    first: First
    last: last
    group: The grouped value
  • parameter bool $useGroupAsIndex (def true), if true, then the result will use the grouped value as index
    if false, then the result will return the values as an indexed array.


/* [
    'cat1' =>
        ['col_min' => 1, 'col_max' => 4, 'col_sum' => 5, 'col_avg' => 2.5, 'col_first' => 'john1', 'col_last' => 'doe4', 'col_count' => 2,],
    'cat2' =>
        ['col_min' => 2, 'col_max' => 5, 'col_sum' => 7, 'col_avg' => 3.5, 'col_first' => 'john2', 'col_last' => 'doe5', 'col_count' => 2,],
    'cat3' =>
        ['col_min' => 3, 'col_max' => 3, 'col_sum' => 3, 'col_avg' => 3, 'col_first' => 'john3', 'col_last' => 'doe3', 'col_count' => 1,],


It converts the index into a field, and renumerates the array

$this->indexToCol('colnew'); // ['a'=>['col1'=>'b','col2'=>'c']] => [['colnew'=>'a','col1'=>'b','col2'=>'c']
  • parameter mixed $newColumn the name of the new column
  • return value $this


Joins the current array with another array
If the columns of both arrays have the same name, then the current name is retained.

$types=[['id'=>123,'desc'=>'it is the type #123']];
// [['id'=>1,'prod'=>'cocacola','idtype'=>123,'desc'=>'it is the type #123']] "id" is from product.
  • parameter array|null $arrayToJoin
  • parameter mixed $column1 the column of the current array
  • parameter mixed $column2 the column of the array to join.
  • return value $this


It returns the last element of an array.

  • return value $this


It calls a function for every element of an array. Example:

$this->map(function($row) { return strtoupper($row); });
  • parameter callable|null $condition The function to call.
  • return value $this


It masks the current array using another array.
Masking deletes all field that are not part of our mask
The mask is smart to recognize a table, so it could mask multiples values by only specifying the first row.

$mask=['a'=>1,'items'=>[[a1'=>1]]; // [[a1'=>1]] masks an entire table
$this->mask($mask); // $array=['a'=>1,'items'=>[[a1'=>1],[a1'=>1]];
  • param array $arrayMask An associative array with the mask. The mask could contain any value.
  • return value ArrayOne


It returns the n-position of an array.

  • parameter $index
  • return value $this


You can reduce (flat) an array using aggregations or a custom function. Example:

$this->reduce(function($row,$index,$prev) { return ['col1'=>$row['col1']+$prev['col1]];  });
  • parameter array|callable $functionAggregation An associative array where the index is the column and the value is the function of aggregation
    A function using the syntax: function ($row,$index,$prev) where $prev is the accumulator value
  • return value $this


It removes a column

  • parameter mixed $colName The name of the column or columns (array)
  • return value $this


It removes the row with the id $rowId. If the row does not exist, then it does nothing Example:

  • parameter mixed $rowId The id of the row to delete
  • parameter bool $renumber if true then it renumber the list
    ex: if 1 is deleted then $renumber=true: [0=>0,1=>1,2=>2] => [0=>0,1=>2]
    ex: if 1 is deleted then $renumber=false: [0=>0,1=>1,2=>2] => [0=>0,2=>2]
  • return value $this


It removes the first row or rows. Numeric index could be renumbered. Example:

$this->removeFirstRow(); // remove the first row
$this->removeFirstRow(3); // remove the first 3 rows
  • parameter int $numberOfRows The number of rows to delete, the default is 1 (the first row)
  • parameter bool $renumber if true then it renumber the list
    ex: if 1 is deleted then $renumber=true: [0=>0,1=>1,'x'=>2] => [0=>0,1=>2]
    ex: if 1 is deleted then $renumber=false: [0=>0,1=>1,2=>2] => [0=>0,2=>2]
  • return value $this


It removes the last row or rows Example:

$this->removeLastRow(); // remove the last row
$this->removeLastRow(3); // remove the last 3 rows
  • parameter int $numberOfRows the number of rows to delete
  • parameter bool $renumber if true then it renumber the list (since we are deleting the last value then usually we don't need it
    ex: if 1 is deleted then $renumber=true: [0=>0,1=>1,2=>2] => [0=>0,1=>2]
    ex: if 1 is deleted then $renumber=false: [0=>0,1=>1,2=>2] => [0=>0,2=>2]
  • return value $this


This function removes duplicates of a table.

  • parameter mixed $colName the column to compare if the rows are duplicated.
  • return value $this


It adds or modify a column. Example:

$this->modCol('col1',function($row,$index) { return $row['col2']*$row['col3'];  });
  • parameter string|int|null $colName the name of the column. If null, then it uses the entire row
  • parameter callable|null $operation the operation to realize.
  • return value $this


Sort an array

$this->sort('payment','desc'); // sort an array using the column paypent descending.
  • parameter mixed $column if column is null, then it sorts the row (instead of a column of the row)
  • parameter string $direction =['asc','desc'][$i] ascending or descending.
  • return value $this


It creates a validation array using an example


Validate the current array using a comparison table

    	 'price'=>'int|between;1,20'   // the price must be an integer and it must be between 1 and 20 (including them).
         'table'=>[['col1'=>'int';'col2'=>'string|notnull,,the value is required|']],   // note the double [[ ]] to indicate a table of values
$valid->all(); // it gets an associative array with all the errors (or null if not error)
$valid->flat()->all(); // if you want a flat result.
$valid->errorStack; // it gets an associative array with only the errors. If nested array, then some values could be overriden.
$valid->isValid(); // returns true if the validation passes, otherwise, it returns false.

Example Using a custom function:

// 1) defining the service class.
class ServiceClass {
     * @param mixed $value the value to evaluate 
     * @param mixed $compare the value to compare (optional)
     * @param ?string $msg the message to return if fails
     * @return bool
    public function test($value,$compare=null,&$msg=null): bool
        return true;
// 2.1) and setting the service class using the class
    ->validate('field'=>'fn:test') // or ->validate('field'=>[['fn','test']])
// 2.2) or you could use an instance
$obj=new ServiceClass();
    ->validate('field'=>'fn:test') // or ->validate('field'=>[['fn','test']])
  • parameter array $comparisonTable The comparison table, is an associative table with the conditions to compare using the next syntax: [index=>"condition|condition2..."].
    • The conditions could be express as: <name of the condition>;<value>;<custom error message>
      • If the <condition> starts with "not", then it is negated, example: "notalpha"
      • The <value> could be a simple literal (1,hello, etc.) or a list of values (separated by comma)
      • The <custom error message> could contain the next variables: %field the id of the field, %value the current value of the field, %comp the value to compare, %first the first value to compare, %second the second value to compare, example "%field (%value) is not equals to %comp", %rowid is the id of the current row (if any)
condition description example work example fail expression
not**<condition>** negates any comparison, excepting nullable and custom functions. Example: "notint" "hello" 20 notint
nullable the value CAN be a null. If the value is null, then it ignores other validations null nullable
f:<namefunction> It calls a custom function defined in the service class. See example "hello" f:test
contain like if a text is contained in "helloworld" "hello" contain;world
alpha if the value is alphabetic "hello" "hello33" alpha
alphanumunder if the value is alphanumeric or under-case "hello_33" "hello!33" alphanumunder
alphanum if the value is alphanumeric "hello33" "hello!33" alphanum
text if the value is a text "hello" true text
regexp if the value match a regular expression. You can't use comma in the regular expression. "abc123" "xyz123" regexp;/abc*/
email if the value is an email "aaa@bbb.com" "aaa.bbb.com" email
url if the value is an url https://www.nic.cl "aaaa" url
domain if the value is a domain www.nic.cl "….." domain
minlen the value must have a minimum length "hello" "h" minlen;3
maxlen the value must have a maximum lenght "h" "hello" maxlen;3
betweenlen if the value has a size between "hello" "h" betweenlen;4,5
exist if the value exists "hi" null exist
missing if the value not exist null "hi" missing
req,required if the value is required "hi" null req,required
eq == if the value is equals to 1 0 eq;1
ne != <> if the value is not equals to 1 0 ne;0
null The value MUST be null. It is different to nullable because nullable is a "CAN" null "hello" null
empty if the value is empty "" "hello" empty
lt if the value is less than 1 10 lt;5
lte/le if the value is less or equals than 1 10 lte;5
gt if the value is great than 10 1 gt;5
gte/ge if the value is great or equals than 10 1 gte;5
between if the value is between 5 0 between;4,5
true if the value is true or 1 true false true
false if the value is false, or 0 false true false
array if the value is an array [1,2,3] 1 array
int if the value is an integer 1 "hello" int
string if the value is a string "hello" true string
float if the value is a float 333.3 "hello" float
object if the value is an object new stdClass() 1 object
in the value must be in a list "a" "x" in;a,b,c
  • parameter bool $extraFieldError if true and the current array has more values than comparison table, then it returns an error.

end operators


Returns the whole array transformed.




returns true if the validation has no error.


if ($this->set($array)->valid($arrayComparison)->isValid()) {
  // do something.

Note: you can also obtain the result of the validation: ->valid($arrayc)->all();
Note2: If you want a simple array with errors, you can use $this::errorStack;


  • return value mixed

other methods

Methods that does not fit in the other categories. Those methods are not stackable.


It generates a validate-array using an example array. It could be used by validation() and filter()

$this->makeValidateArrayByExample(['1','a','f'=>3.3]); // ['int','string','f'=>'float'];
  • parameter array $array
  • return value array


It creates an associative array that could be used to be used by setRequest()

$this->makeRequestArrayByExample(['a'=1,'b'=>2]); // ['a'='post','b'=>'post'];
  • parameter array $array An associative array with some values.
  • parameter string $type=['get','post','request','header','cookie'][$i] The default type
  • return value array


  • 2.00 2024-03-10
    • nav() and currentArray() are removed from 2.0. The library was optimized and streamlined, and those functions are redundant.
// before:
// now:
// before:
// now:
  • 1.12 2024-03-01
    • Updating dependency to PHP 7.4. The extended support of PHP 7.2 ended 3 years ago.
  • 1.11 2024-03-01
    • added method find()
    • aedded method isIndexArray() and isIndexTableArray()
    • now find() and filter() allows multiple conditions
    • and find() and filter(), the condition ['field'='eq;2'] could be written as ['field','2']
  • 1.10 2024-02-24
    • Added more doc for validate()
    • Now validate also returns an array $this::$errorStack
    • New method isValid() which returns true is validate has no error. Otherwise false.
  • 1.9 2023-11-13
    • added rowToValue()
  • 1.8.3 2023-09-16
    • offsetGet() generates a warning in php 8.1 (fixed)
    • current() is marked as deprecated (but it is still functional), use getCurrent()
  • 1.8.2 2023-09-16
    • solved a psr-4 problem in composer.json
  • 1.8.1 2023-09-16
    • change the PHPDOC comments, now it uses markdown instead of "pre" tag.
    • Added ArrayAccess interface.
  • 1.8 2023-07-29
    • [mod] group() allows to specify a custom function(s).
  • 1.7 2023-06-04
    • [new] group() allows returning the grouped value. It also allows returning the values as an indexed array.
  • 1.6 2023-04-10
    • [optimization] setCurrentArray() now is only used when nav() is called or when the value is returned.
  • 1.5 2023-04-07
    • [new] filtercondition() now allow conditions as array.
  • 1.4 2023-04-05
    • [fix] filtercondition() fixed a warning when the value is null.
    • [new] group() now allow to stack elements
    • [new] group() now allow to specify a new column
  • 1.3 2023-03-31
    • validation now allow negation ("not" prefix).
  • 1.2
    • renamed method getValidateArrayByExample() to makeValidateArrayByExample()
    • new method makeRequestArrayByExample()
    • new method setRequest()
    • rename method setCol() to modCol(). Methods that start with "set" are used to initialize the variable.
  • 1.1 2023-03-28
    • method filter() now allow a comparison array and a callable function.
    • new method getValidateArrayByExample()
    • new method removeRow()
    • new method removeFirstRow()
    • new mehtod removeLastRow()
    • new method setCsv()
    • new method setJson()
  • 1.0 2023-03-26 first version


Copyright Jorge Castro Castillo 2023-2024. Licensed under dual license: LGPL-3.0 and commercial license.

In short:

  • Can I use in a close source application for free? Yes if you don't modify this library.
  • If you modify it, then you must share the source code.
  • If you want to modify privately, then you must buy a license.