XO is a library that provides some e(x)tended (o)bjects to build strictly typed arrays such as Map, Set, Tuple or any type of TypedArray's, and also String and Number objects that are not objects natively in PHP.
You can use Map
, Set
and Tuple
to build strict arrays and also use AnyArray
(ArrayObject
and Collection
are just aliases of it) derived from AbstractArray
that contains many native-equal array methods or StringObject
and NumberObject
to use AbstractScalarObject
interface.
All XO objects extends AbstractObject
, so that makes possible to use some basic object methods like getName()
or getShortName()
.
use xo\Collection;
use function xo\set;
// Declare a typed array as Poll
class Poll extends Collection {
// Define a custom method
public function getResults(): array {
// Use copy(), so do not modify Poll instance
return $this->copy()->map(function ($option) {
// Use set() shortcut and sum avarage of option values
return set($option)->sumAvg(2);
})->sort('asort', function ($a, $b) {
// Use reverse sort preserving keys
return $a < $b;
})->toArray();
}
}
// Create an instance of Poll
$poll = new Poll([
// Fill with options
'option_1' => [2, 2, 1],
'option_2' => [5, 1, 5],
'option_3' => [3, 5, 2]
]);
var_export($poll->getResults()); //=> ['option_2' => 3.67, 'option_3' => 3.33, 'option_1' => 1.67]
composer require k-gun/xo
Use can also download and use without Composer including boot.php
.
include 'path_to_xo/boot.php';
Basically there are 5 types of array in XO;
TypedArray: Int
or String
keyed object derived from AbstractArray.
$array = new xo\TypedArray('IntArray', [1, 2, 3], 'int');
$array->sum(); //=> 6
$array->append(4);
$array->sum(); //=> 10
// this will throw a xo\exception\MethodException
// 'cos append() does not take string value
$array->append('4');
AnyArray: String
keyed object derived from TypedArray.
$map = new xo\AnyArray(['a' => 1, 'b' => 2]);
$map->sum(); //=> 3
// add new item
$map->append(3);
$map->sum(); //=> 6
Map: String
keyed object derived from TypedArray.
$map = new xo\Map(['a' => 1, 'b' => 2]);
$map->sum(); //=> 3
// this will throw a xo\exception\MethodException
// 'cos append() does not take a key but only value
$map->append(3);
// add new item with key,value pairs using set(), or push() as well
$map->set('c', 3);
$map->sum(); //=> 6
Set: Int
keyed object derived from TypedArray.
$map = new xo\Set(1, 2);
$map->sum(); //=> 3
// add new item without key
$map->append(3);
// or with key,value pairs using set(), or push() as well
$map->set(2, 3);
$map->sum(); //=> 6
Tuple: Int
keyed and read-only
object derived from TypedArray.
$map = new xo\Tuple(1, 2);
$map->sum(); //=> 3
// this will throw a xo\exception\MethodException
// 'cos append() is not allowed for Tuple objects
$map->append(3);
But, off course, you can create new typed array objects via TypedArray
directly like in first example or defining new arrays that extend TypedArray
or other objects such as Map
, Set
, Tuple
or AnyArray
.
Typed array example;
class IntArray extends xo\TypedArray {
public function __construct(array $items = null) {
parent::__construct('IntArray', $items, 'int');
}
}
$array = new IntArray();
$array->append(1);
$array->append(2);
$array->append('3'); //=> error
Yet another example;
class Poll extends xo\TypedArray {
public function __construct(array $items = null) {
parent::__construct('Poll', $items, 'array');
}
public function getResults(): array {
return $this->copy()->map(function ($option) {
return round(array_sum($option) / count($option), 2);
// or
// return xo\set($option)->sumAvg(2);
// return (new xo\Set($option))->sumAvg(2);
})->sort('asort', function ($a, $b) {
return $a < $b;
})->toArray();
}
}
$poll = new Poll();
$poll->put('option_1', [2, 2, 1]);
$poll->put('option_2', [5, 1, 5]);
$poll->put('option_3', [3, 5, 2]);
var_export($poll->getResults()); //=> ['option_2' => 3.67, 'option_3' => 3.33, 'option_1' => 1.67]
If you want to make a untyped array, you can simply use AnyArray
. So that will provide all methods as well likely on the other arrays.
Here is another example with AnyArray
like above;
class Poll extends xo\AnyArray {
public function getResults(): array {
return $this->copy()->map(function ($option) {
return round(array_sum($option) / count($option), 2);
})->sort('asort', function ($a, $b) {
return $a < $b;
})->toArray();
}
}
Creating custom arrays;
class User {
private $id;
public function __construct(int $id = null) {
$this->id = $id;
}
}
class Users extends xo\TypedArray {
public function __construct(array $items = null) {
parent::__construct('Users', $items, User::class);
}
}
$users = new Users();
$users->add(new User(1));
$users->add(new User(2));
$users->add(new User(null));
var_dump($users->copy()->filter(function (User $user) {
return !is_null($user->id);
})->count()); //=> int(2)
// this will throw a xo\exception\ValueException
// 'cos Users accepts User type values only
$users->add('boom!');
Besides, it also possible with Set
or Map
;
class Users extends xo\Set {
public function __construct(array $items = null) {
parent::__construct($items, User::class);
}
}
$users = new Users();
$users->add(new User(1));
$users->add(new User(2));
$users->add(new User(null));
...
// or
class Users extends xo\Map {
public function __construct(array $items = null) {
parent::__construct($items, User::class);
}
}
$users = new Users();
$users->put(1, new User(1));
$users->put(2, new User(2));
$users->put('null', new User(null));
...
$string = new xo\StringObject('Hello, world!');
var_dump($string->test('~hell~')); //=> bool(false)
var_dump($string->test('~hell~i')); //=> bool(true)
var_dump($string->startsWith('He')); //=> bool(true)
$number = new xo\NumberObject(1.555);
var_dump($number->toInt()); //=> int(1)
var_dump($number->toFloat()); //=> float(1.555)
var_dump($number->toFloat(2)); //=> float(1.56)
-
abstract class xo\AbstractObject {} public final getClass(): object public final getName(): string public final getShortName(): string public final clone(): object public final equals(object $object): bool throws xo\exception\MethodException public toValue(): ?any public toString(): string
-
abstract class xo\AbstractArray extends xo\AbstractObject implements xo\ArrayInterface, Countable, IteratorAggregate {} use xo\ArrayTrait private bool $readOnly private bool $allowNulls private xo\ArrayObject $items private string $itemsType private static array $methods protected static array $notAllowedMethods public __construct(array $items = null, string $itemsType = null, bool $readOnly = false, bool $allowNulls = false) public final __call(string $method, array $methodArgs): any throws xo\exception\MethodException public final prototype(string $method, callable $methodFunc): void throws xo\exception\MethodException public final readOnly(): bool public final allowNulls(): bool public final item($key): ?any public final items(bool $pair = false): array public final itemsType(): string public final reset(array $items): self throws xo\exception\MutationException public final resetItems(array $items): self throws xo\exception\MutationException public final copy(): xo\ArrayInterface public final copyArray(): array public final size(): int public final empty(): void public final isEmpty(): bool public final count(): int public final countValues(): array public final keys(): array public final values(): array public final first(): ?any public final firstKey(): int|string|null public final last(): ?any public final lastKey(): int|string|null public final toArray(bool $normalize = false): array public final toObject(): object public final toJson(): string public final map(callable $func): self throws xo\exception\MutationException public final reduce($initialValue = null, callable $func = null): any public final filter(callable $func = null): self throws xo\exception\MutationException public final diff(iterable $items, bool $uniq = false): array public final uniq(): array public final ununiq(): array public final uniqs(): array public final merge(self $array): self throws xo\exception\MutationException,ArgumentException public final chunk(int $size, bool $preserveKeys = false): array public final slice(int $offset, int $size = null, bool $preserveKeys = false): array public final reverse(): self public final rand(int $size = 1, bool $useKeys = false) public final shuffle(bool $preserveKeys = null): self throws xo\exception\MutationException public final sort(callable $func = null, callable $ufunc = null, int $flags = 0): self throws xo\exception\MutationException public final sortNatural(bool $caseSensitive = true, int $flags = 0): self throws xo\exception\MutationException public final sortLocale(string $locale, callable $func = null, callable $ufunc = null, int $flags = 0): self throws xo\exception\MutationException public final test(Closure $func): bool public final testAll(Closure $func): bool public final find(Closure $func): ?any public final findKey(Closure $func): int|string|null public final findIndex(Closure $func): ?int public final keyCheck(int|string $key): void throws xo\exception\KeyException public final valueCheck(any $value): void throws xo\exception\ValueException public final keyValueCheck(int|string $key, any $value): void throws xo\exception\KeyException,ValueException public final nullCheck(any $value): void throws xo\exception\NullException public final methodCheck(string $method): void throws xo\exception\MethodException public final readOnlyCheck(): void throws xo\exception\MutationException public final generate(bool $reverse = false): Generator public final getIterator(): Generator public final min(bool $numericsOnly = false): ?any public final max(bool $numericsOnly = false): ?any public final calc(string $operator, int $round = null, int &$valueCount = null): ?number throws xo\ArrayException public final calcAvg(string $operator, int $round = null, int &$valueCount = null): ?float throws xo\ArrayException public final sum(int $round = null, int &$valueCount = null): ?number public final sumAvg(int $round = null, int &$valueCount = null): ?float private final executeCommand(string $command, &...$arguments): void throws xo\exception\MutationException,NullException throws xo\ArrayException
-
class xo\TypedArray extends xo\AbstractArray {} protected string $type; public __construct(string $type, array $items = null, string $itemsType = null, bool $readOnly = false, bool $allowNulls = false) throws xo\exception\TypeException public final type(): string
-
class xo\AnyArray extends xo\TypedArray {} protected static array $notAllowedMethods = [] public __construct(array $items = null, bool $readOnly = false) public search(any $value): int|string|null public searchLast(any $value): int|string|null public indexOf(any $value): ?int public lastIndexOf(any $value): ?int public has(any $value): bool public hasKey(int|string $key): bool public set(int|string $key, any $value, int &$size = null): self public get(int|string $key, any $valueDefault = null, bool &$found = null): ?any public add(any $value): self public remove(any $value, bool &$found = null): self public removeAt(int|string $key, bool &$found = null): self public removeAll(array $values, int &$count = null): self public append(any $value, int &$size = null): self public prepend(any $value, int &$size = null): self public pop(int &$size = null): ?any public unpop(any $value, int &$size = null): self public shift(int &$size = null): ?any public unshift(any $value, int &$size = null): self public put(int|string $key, any $value): self public push(int|string $key, any $value): self public pull(int|string $key, any $valueDefault = null, bool &$found = null): ?any public replace(any $value, any $replaceValue, bool &$found = null): self public replaceAt(int|string $key, any $replaceValue, bool &$found = null): self public flip(): self throws xo\ArrayException public pad(int $times, any $value, int $offset = null): self
-
class xo\Map extends xo\TypedArray {} protected static array $notAllowedMethods = ['flip', 'add', 'append', 'prepend', 'unpop', 'unshift', 'flip', 'pad'] public __construct(array $items = null, string $itemsType = null, bool $readOnly = false, bool $allowNulls = false) public search(any $value): int|string|null public searchLast(any $value): int|string|null public indexOf(any $value): ?int public lastIndexOf(any $value): ?int public has(any $value): bool public hasKey(string $key): bool public set(string $key, any $value, int &$size = null): self public get(string $key, any $valueDefault = null, bool &$found = null): ?any public remove(any $value, bool &$found = null): self public removeAt(string $key, bool &$found = null): self public removeAll(array $values, int &$count = null): self public pop(int &$size = null): ?any public shift(int &$size = null): ?any public put(string $key, any $value): self public push(string $key, any $value): self public pull(string $key, any $valueDefault = null, bool &$found = null): ?any public replace(any $value, any $replaceValue, bool &$found = null): self public replaceAt(string $key, any $replaceValue, bool &$found = null): self
-
class xo\Set extends xo\TypedArray {} protected static array $notAllowedMethods = ['flip'] public __construct(array $items = null, string $itemsType = null, bool $readOnly = false, bool $allowNulls = false) public search(any $value): int|string|null public searchLast(any $value): int|string|null public indexOf(any $value): ?int public lastIndexOf(any $value): ?int public has(any $value): bool public hasKey(int $key): bool public set(int $key, any $value, int &$size = null): self public get(int $key, any $valueDefault = null, bool &$found = null): ?any public add(any $value): self public remove(any $value, bool &$found = null): self public removeAt(int $key, bool &$found = null): self public removeAll(array $values, int &$count = null): self public append(any $value, int &$size = null): self public prepend(any $value, int &$size = null): self public pop(int &$size = null): ?any public unpop(any $value, int &$size = null): self public shift(int &$size = null): ?any public unshift(any $value, int &$size = null): self public put(int $key, any $value): self public push(int $key, any $value): self public pull(int $key, any $valueDefault = null, bool &$found = null): ?any public replace(any $value, any $replaceValue, bool &$found = null): self public replaceAt(int $key, any $replaceValue, bool &$found = null): self public pad(int $times, any $value, int $offset = null): self
-
class xo\Tuple extends xo\TypedArray {} protected static array $notAllowedMethods = ['reset', 'resetItems', 'empty', 'map', 'filter', 'merge', 'reverse', 'shuffle', 'search', 'searchLast', 'set', 'add', 'remove', 'removeAt', 'removeAll', 'append', 'prepend', 'pop', 'unpop', 'shift', 'unshift', 'put', 'push', 'pull', 'replace', 'replaceAt', 'flip', 'pad'] public __construct(array $items = null, string $itemsType = null, bool $allowNulls = false) public indexOf(any $value): ?int public lastIndexOf(any $value): ?int public has(any $value): bool public hasKey(int $key): bool public get(int $key, any $valueDefault = null, bool &$found = null): ?any
-
// these are just aliased classes class xo\ArrayObject extends xo\AnyArray {} class xo\Collection extends xo\AnyArray {}
-
abstract class xo\AbstractScalarObject extends xo\AbstractObject {} protected scalar $value; protected string $valueType; public __construct(scalar $value) throws xo\exception\ArgumentTypeException public final value(): scalar public final valueType(): string public final equalsTo(scalar $value): bool public final size(bool $multiByte = false): int public toString(): string
-
class xo\StringObject extends xo\AbstractScalarObject {} public string const TRIM_CHARS = " \t\n\r\0\x0B" public __construct(string $value) throws xo\exception\ArgumentTypeException public final test(string $pattern): ?bool public final match(string $pattern, int $flags = 0): ?array public final matchAll(string $pattern, int $flags = 0): ?array public final indexOf(string $search, bool $caseSensitive = true): ?int public final lastIndexOf(string $search, bool $caseSensitive = true): ?int public final trim(string $chars = null, int $side = 0): string public final trimLeft(string $chars = null): string public final trimRight(string $chars = null): string public final trimSearch(string $search, bool $caseSensitive = true, int $side = 0): string public final trimSearches(array[string] $searches, bool $caseSensitive = true, int $side = 0): string public final compare(string $value): int public final compareLocale(string $locale, string $value): int public final contains(string $search, bool $caseSensitive = true): bool public final containsAny(array[string] $searches, bool $caseSensitive = true): bool public final containsAll(array[string] $searches, bool $caseSensitive = true): bool public final startsWith(string $search): bool public final endsWith(string $search): bool
-
class xo\NumberObject extends xo\AbstractScalarObject {} public __construct(numeric $value) throws xo\exception\ArgumentTypeException public final toInt(): int public final toFloat(int $round = null): float
-
static class xo\StaticClass {} public final __construct() throws xo\StaticClassException
-
static final class xo\Type extends xo\StaticClass {} public const ANY = 'Any' public const MAP = 'Map' public const SET = 'Set' public const TUPLE = 'Tuple' public static validateItems(object $object, string $type, array $items, string $itemsType = null, bool $allowNulls, string &$error = null): bool public static get(any $input, bool $objectCheck = false): string public static export(any $input): string public static makeArray(any $input): array public static makeObject(any $input): object public static isBasic(string $type): bool public static isDigit(any $input, bool $negatives = false): bool public static isTuple(any $input): bool public static isMapLike(any $input): bool public static isSetLike(any $input): bool
-
static class xo\util\Util extends xo\StaticClass {}
-
static class xo\util\ArrayUtil extends xo\util\Util {} public static final keyCheck(int|string $key): ?string throws xo\util\UtilException public static final isSequentialArray(array $array): bool public static final isAssociativeArray(array $array): bool public static final set(array &$array, int|string $key, any $value): array throws xo\util\UtilException public static final get(array $array, int|string $key, any $valueDefault = null): ?any throws xo\util\UtilException public static final getAll(array $array, array[int|string] $keys, any $valueDefault = null): array throws xo\util\UtilException public static final pull(array &$array, int|string $key, any $valueDefault = null): ?any throws xo\util\UtilException public static final pullAll(array &$array, array[int|string] $keys, any $valueDefault = null): array throws xo\util\UtilException public static final test(array $array, Closure $func): bool public static final testAll(array $array, Closure $func): bool public static final rand(array $items, int $size = 1, bool $useKeys = false) throws xo\util\UtilException public static final shuffle(array &$items, bool $preserveKeys = false): array public static final sort(array &$array, callable $func = null, callable $ufunc = null, int $flags = 0): array throws xo\util\UtilException public static final include(array $array, array $keys): array public static final exclude(array $array, array $keys): array public static final first(array $array, any $valueDefault = null): ?any public static final last(array $array, any $valueDefault = null): ?any public static final getInt(array $array, int|string $key, int $valueDefault = null): int public static final getFloat(array $array, int|string $key, float $valueDefault = null): float public static final getString(array $array, int|string $key, string $valueDefault = null): string public static final getBool(array $array, int|string $key, bool $valueDefault = null): bool
-
static class xo\util\NumberUtil extends xo\util\Util {} public static final compare(number $a, number $b, int $precision = null): ?int public static final equals(number $a, number $b, int $precision = null): ?bool public static final isNumber(any $input): bool public static final isDigit(any $input, bool $negatives = false): bool public static final isId(any $input): bool public static final isUInt(any $input): bool public static final isUFloat(any $input): bool public static final isSigned(any $input): bool public static final isUnsigned(any $input): bool
-
static class xo\util\StringUtil extends xo\util\Util {} public static final compare(string $source1, string $source2): int public static final compareLocale(string $locale, string $source1, string $source2): int public static final contains(string $source, string $search, bool $caseSensitive = true): bool public static final containsAny(string $source, array $searches, bool $caseSensitive = true): bool public static final containsAll(string $source, array $searches, bool $caseSensitive = true): bool public static final startsWith(string $source, string $search): bool public static final endsWith(string $source, string $search): bool public static final trimSearch(string $source, string $search, bool $caseSensitive = true, int $side = 0): string
class xo\exception\Exception extends Exception {}
class xo\ArrayException extends xo\exception\Exception {}
class xo\StaticClassException extends xo\exception\Exception {}
class xo\util\UtilException extends xo\exception\Exception {}
class xo\exception\ArgumentException extends xo\exception\Exception {}
class xo\exception\ArgumentTypeException extends xo\exception\Exception {}
class xo\exception\KeyException extends xo\exception\Exception {}
class xo\exception\ValueException extends xo\exception\Exception {}
class xo\exception\MethodException extends xo\exception\Exception {}
class xo\exception\MutationException extends xo\exception\Exception {}
class xo\exception\NullException extends xo\exception\Exception {}
class xo\exception\TypeException extends xo\exception\Exception {}
map(...$arguments): xo\Map
set(...$arguments): xo\Set
tuple(...$arguments): xo\Tuple
collection(...$arguments): xo\Collection
string(string $value): xo\StringObject
number(numeric $value): xo\NumberObject