Collection¶
Overview¶
Phalcon\Support\Collection is an object-oriented array. It offers speed, as well as implementations of various PHP interfaces. These are:
In addition to the interfaces, Collection exposes a rich method set for inspecting, transforming, and filtering the data it holds. The component is meant to be used wherever the application needs an object-flavored array that supports both property/array access and higher-order operations like filter(), map(), reduce(), and sort().
<?php
use Phalcon\Support\Collection;
$data = [
'colors' => [
'red',
'green',
'blue',
],
'year' => 1987,
];
$collection = new Collection($data);
Constructor¶
public function __construct(
array $data = [],
bool $insensitive = true,
bool $strictNull = false,
string | null $type = null
)
Collection accepts four optional constructor parameters. Each is described in its own section below, but here is the full surface at a glance:
| Parameter | Type | Default | Purpose |
|---|---|---|---|
$data | array | [] | Initial payload. The collection is populated by calling init($data). |
$insensitive | bool | true | When true, key lookups are case-insensitive. |
$strictNull | bool | false | When true, a stored null value is returned verbatim by get(). |
$type | string\|null | null | Optional runtime type guard enforced on every set() / init() call. |
The simplest construction passes only the initial payload:
<?php
use Phalcon\Support\Collection;
$data = [
'colors' => [
'red',
'green',
'blue',
],
'year' => 1987,
];
$collection = new Collection($data);
Case Sensitivity¶
The second constructor parameter, $insensitive, controls how key lookups behave. With the default true, all keys are normalized to lowercase on read and write, so get('year'), get('Year'), and get('YEAR') all return the same value. Setting it to false makes every key comparison exact.
<?php
use Phalcon\Support\Collection;
$data = [
'colors' => [
'red',
'green',
'blue',
],
'year' => 1987,
];
$collection = new Collection($data, false);
echo $collection->has('year'); // true
echo $collection->has('COLORS'); // false (would be true with $insensitive = true)
Strict Null Handling¶
The third constructor parameter, $strictNull, changes how get() reports stored null values:
false(default): a storednullis treated as "missing" and the supplied default (ornullif no default is given) is returned. This matches the long-standing 3.x behavior.true: a storednullis returned as-is. Use this when you need to distinguish "I storednullon purpose" from "the key was never set".
<?php
use Phalcon\Support\Collection;
$loose = new Collection(['flag' => null], true, false);
$strict = new Collection(['flag' => null], true, true);
echo $loose->get('flag', 'fallback'); // 'fallback' — null treated as missing
echo $strict->get('flag', 'fallback'); // null — null returned verbatim
has() is unaffected by $strictNull — it reports membership, not value. A key whose stored value is null always satisfies has().
Type Guard¶
The fourth constructor parameter, $type, turns the collection into a typed container. When set, every set() and every value assigned through init() (or via __set, offsetSet, or the property syntax) is validated against $type. A mismatched value triggers an InvalidArgumentException and is not stored.
The accepted tokens are split into two groups:
Scalar tokens map to the corresponding is_* checks:
| Token | Check |
|---|---|
'int' | is_int() |
'string' | is_string() |
'bool' | is_bool() |
'float' | is_float() |
'array' | is_array() |
'object' | is_object() |
Anything else is treated as a fully-qualified class or interface name and tested with instanceof.
<?php
use Phalcon\Support\Collection;
use Phalcon\Mvc\Url;
// Scalar guard — only integers allowed
$years = new Collection([], true, false, 'int');
$years->set('genesis', 1987); // OK
$years->set('genesis', '1987'); // InvalidArgumentException — '1987' is a string
// Class guard — only Url instances allowed
$urls = new Collection([], true, false, Url::class);
$urls->set('home', new Url()); // OK
$urls->set('home', '/home'); // InvalidArgumentException
The guard runs on the initial payload as well, so passing data that does not match the declared type will throw at construction time:
$years = new Collection(['ok' => 1, 'bad' => 'two'], true, false, 'int');
// InvalidArgumentException is thrown while iterating the initial array
You can read the configured guard back at any time with getType() (see below). When $type is null (the default), the guard is a no-op and any value is accepted.
Reusing¶
You can also reuse the component by repopulating it. Phalcon\Support\Collection exposes three methods to manage the internal data wholesale:
clear()— empties the collection.init(array $data = [])— adds each entry of$datato the collection without clearing first. Existing keys are overwritten; other keys are left untouched.replace(array $data)— clear-then-init in one call. Useful when you want a clean swap.
<?php
use Phalcon\Support\Collection;
$data = [
'colors' => [
'red',
'green',
'blue',
],
'year' => 1987,
];
$collection = new Collection($data);
echo $collection->count(); // 2
// Wholesale swap
$collection->replace(['year' => 1987]);
echo $collection->count(); // 1
// Or the two-step variant
$collection->clear();
$collection->init(['year' => 1987]);
echo $collection->count(); // 1
Get¶
Phalcon\Support\Collection implements several interfaces to make the component as flexible as possible. Retrieving data stored in an element can be done by using:
- Property access
__get()- Array-based get (
$collection[$element]) offsetGet()get()
The fastest way is by using the property syntax:
<?php
use Phalcon\Support\Collection;
$data = [
'colors' => [
'red',
'green',
'blue',
],
'year' => 1987,
];
$collection = new Collection($data);
echo $collection->year; // 1987
You can use __get($element) but it is not advisable as it is much slower than the property syntax. The same applies to offsetGet:
echo $collection->__get('year'); // 1987
echo $collection['year']; // 1987
echo $collection->offsetGet('year'); // 1987
echo $collection->get('year', 1987); // 1987
public function get(
string $element,
mixed $defaultValue = null,
string | null $cast = null
): mixed
get() offers three parameters:
$element— the key of the element we want to retrieve.$defaultValue— returned when$elementis not set, or when$elementis set tonulland$strictNullisfalse(the default). See Strict Null Handling for the strict variant.$cast— accepts a string that defines what the returned value will be cast to before it is returned. The available values are:arrayboolbooleandoublefloatintintegernullobjectstring
$collection = new Collection(['port' => '8080']);
echo $collection->get('port', null, 'int'); // (int) 8080
Has¶
To check whether an element exists or not in the collection, you can use the following:
isset()on the property__isset()- Array-based isset (
isset($collection[$element])) offsetExists()has()
The fastest way is by using the property syntax:
<?php
use Phalcon\Support\Collection;
$data = [
'colors' => [
'red',
'green',
'blue',
],
'year' => 1987,
];
$collection = new Collection($data);
echo isset($collection->year); // true
You can use __isset($element) but it is not advisable as it is much slower than the property syntax. The same applies to offsetExists:
echo $collection->__isset('year'); // true
echo isset($collection['year']); // true
echo $collection->offsetExists('year'); // true
echo $collection->has('year'); // true
Set¶
To set an element in the collection, you can use the following:
- Assign the value to the property
__set()- Array-based assignment
offsetSet()set()
The fastest way is by using the property syntax:
<?php
use Phalcon\Support\Collection;
$data = [
'colors' => [
'red',
'green',
'blue',
],
];
$collection = new Collection($data);
$collection->year = 1987;
You can use __set($element, $value) but it is not advisable as it is much slower than the property syntax. The same applies to offsetSet:
$collection->__set('year', 1987);
$collection['year'] = 1987;
$collection->offsetSet('year', 1987);
$collection->set('year', 1987);
Every code path above ultimately routes through the same internal setData() helper, which means the Type Guard (when configured) applies uniformly regardless of which form you use.
Remove¶
To remove an element in the collection, you can use the following:
unsetthe property__unset()- Array-based unset
offsetUnset()remove()
The fastest way is by using the property syntax:
<?php
use Phalcon\Support\Collection;
$data = [
'colors' => [
'red',
'green',
'blue',
],
];
$collection = new Collection($data);
unset($collection->year);
You can use __unset($element) but it is not advisable as it is much slower than the property syntax. The same applies to offsetUnset:
$collection->__unset('year');
unset($collection['year']);
$collection->offsetUnset('year');
$collection->remove('year');
Keys and Values¶
Collection exposes two methods to read the internal data shape directly:
keys(bool $insensitive = true): array— returns the keys stored internally. With the defaulttrue, keys are returned in their case-insensitive (lowercase) form, mirroring how they were indexed. Passfalseto receive the keys in their original casing.values(): array— returns the values, indexed numerically from0.
<?php
use Phalcon\Support\Collection;
$data = [
'Year' => 1987,
'colors' => ['red', 'green', 'blue'],
];
$collection = new Collection($data);
print_r($collection->keys()); // ['year', 'colors']
print_r($collection->keys(false)); // ['Year', 'colors']
print_r($collection->values()); // [1987, ['red', 'green', 'blue']]
NOTE
The original method names getKeys() and getValues() are retained as deprecated thin wrappers over keys() / values(). New code should call keys() and values() directly. The deprecated forms will be removed in a future major release.
Inspecting¶
The following methods give you quick visibility into the collection without iterating it yourself:
count(): int— number of stored elements (also satisfiesCountable).isEmpty(): bool—truewhen the collection holds no elements.first(): mixed— first stored value, ornullwhen empty.last(): mixed— last stored value, ornullwhen empty.getType(): string | null— the type guard configured at construction (see Type Guard), ornullwhen none.column(string $propertyOrMethod): array— projects a single property (or method-result) off every stored item, keyed by the original collection key.
<?php
use Phalcon\Support\Collection;
$collection = new Collection([
'one' => 1,
'two' => 2,
'three' => 3,
]);
echo $collection->count(); // 3
echo $collection->isEmpty(); // false
echo $collection->first(); // 1
echo $collection->last(); // 3
echo $collection->getType(); // null
column() accepts the name of either a public property or a public method. For each stored item it returns the property's value, or the result of invoking the method with no arguments. Items that are not objects/arrays are returned as null.
<?php
use Phalcon\Support\Collection;
class User
{
public function __construct(
public string $name,
public int $age,
) {}
public function displayName(): string
{
return strtoupper($this->name);
}
}
$users = new Collection([
'alice' => new User('Alice', 30),
'bob' => new User('Bob', 25),
]);
print_r($users->column('age'));
// ['alice' => 30, 'bob' => 25]
print_r($users->column('displayName'));
// ['alice' => 'ALICE', 'bob' => 'BOB']
column() also works on plain arrays:
$rows = new Collection([
['id' => 1, 'name' => 'Alice'],
['id' => 2, 'name' => 'Bob'],
]);
print_r($rows->column('name')); // [0 => 'Alice', 1 => 'Bob']
Filtering and Transforming¶
Collection exposes a small set of higher-order operations modeled after the standard array primitives. Each of these returns a new Collection of the same concrete subclass (so Registry::filter(...) returns a Registry, not a base Collection) and carries over the insensitive, strictNull, and type configuration; the source collection is never mutated.
each(callable $callback)¶
Runs $callback($value, $key) for every entry and returns the collection itself, so calls can be chained. Use this for side effects (logging, dispatching events) where you do not need a new collection back.
<?php
use Phalcon\Support\Collection;
$collection = new Collection(['one' => 1, 'two' => 2, 'three' => 3]);
$collection
->each(function ($value, $key) {
echo "$key => $value" . PHP_EOL;
})
->each(function ($value) {
// do something else
});
filter(callable $callback)¶
Returns a new collection containing only the entries for which $callback($value, $key) returns a truthy value. Original keys are preserved.
<?php
use Phalcon\Support\Collection;
$collection = new Collection([
'one' => 1,
'two' => 2,
'three' => 3,
'four' => 4,
]);
$even = $collection->filter(
fn ($value) => $value % 2 === 0
);
print_r($even->toArray()); // ['two' => 2, 'four' => 4]
map(callable $callback)¶
Returns a new collection with every entry replaced by $callback($value, $key). Keys are preserved.
<?php
use Phalcon\Support\Collection;
$collection = new Collection(['one' => 1, 'two' => 2, 'three' => 3]);
$squared = $collection->map(
fn ($value) => $value * $value
);
print_r($squared->toArray()); // ['one' => 1, 'two' => 4, 'three' => 9]
reduce(callable $callback, mixed $initial = null)¶
Collapses the collection to a single value by repeatedly applying $callback($accumulator, $value, $key). The first call receives $initial as the accumulator; each subsequent call receives the previous return value.
<?php
use Phalcon\Support\Collection;
$collection = new Collection(['one' => 1, 'two' => 2, 'three' => 3]);
$sum = $collection->reduce(
fn ($acc, $value) => $acc + $value,
0
);
echo $sum; // 6
sort(?callable $callback = null, int $order = SORT_ASC)¶
Returns a new collection sorted by value, preserving keys. When $callback is supplied it is passed to PHP's uasort. Without a callback, the comparison direction is controlled by $order (SORT_ASC uses asort(), SORT_DESC uses arsort()).
<?php
use Phalcon\Support\Collection;
$collection = new Collection([
'c' => 30,
'a' => 10,
'b' => 20,
]);
print_r($collection->sort()->toArray());
// ['a' => 10, 'b' => 20, 'c' => 30]
print_r($collection->sort(null, SORT_DESC)->toArray());
// ['c' => 30, 'b' => 20, 'a' => 10]
$byLength = $collection
->map(fn ($v) => str_repeat('x', $v / 10))
->sort(fn ($left, $right) => strlen($left) <=> strlen($right));
where(string $propertyOrMethod, mixed $value)¶
Returns a new collection containing only the items whose $propertyOrMethod (resolved through the same logic as column()) is strictly equal (===) to $value.
<?php
use Phalcon\Support\Collection;
$users = new Collection([
['id' => 1, 'role' => 'admin'],
['id' => 2, 'role' => 'user'],
['id' => 3, 'role' => 'admin'],
]);
$admins = $users->where('role', 'admin');
print_r($admins->toArray());
// [
// 0 => ['id' => 1, 'role' => 'admin'],
// 2 => ['id' => 3, 'role' => 'admin'],
// ]
Iteration¶
Since the collection object implements \IteratorAggregate, you can iterate through the object with ease. getIterator() returns an ArrayIterator instance.
<?php
use Phalcon\Support\Collection;
$data = [
'red',
'green',
'blue',
];
$collection = new Collection($data);
foreach ($collection as $key => $value) {
echo $key . ' - ' . $value . PHP_EOL;
}
Count¶
The implementation of the \Countable interface exposes the count() method, which stores the number of elements in the collection.
<?php
use Phalcon\Support\Collection;
$data = [
'colors' => [
'red',
'green',
'blue',
],
'year' => 1987,
];
$collection = new Collection($data);
echo $collection->count(); // 2
echo count($collection); // 2 (same value, via Countable)
Serialization¶
The \Serializable and \JsonSerializable interfaces expose methods that allow you to serialize and unserialize the object. serialize() and unserialize() use PHP's serialize / unserialize functions; jsonSerialize() returns an array which can be used with json_encode to serialize the object.
__serialize() returns a structured array that captures the full collection configuration — data, insensitive, strictNull, and type — so that round-tripping through serialize()/unserialize() faithfully restores the case-sensitivity setting, the strict-null mode, and the type guard, not just the data.
<?php
use Phalcon\Support\Collection;
$data = [
'colors' => [
'red',
'green',
'blue',
],
'year' => 1987,
];
$collection = new Collection($data, false, true, 'int');
$blob = $collection->serialize();
// O:31:"Phalcon\Support\Collection":4:{...}
// Contains data + insensitive=false + strictNull=true + type=int
$restored = new Collection();
$restored->unserialize($blob);
echo $restored->getType(); // 'int' — guard preserved
Backwards compatibility
__unserialize() accepts both the new structured format and the legacy flat-array format produced by earlier releases, so existing serialized blobs stored in caches, sessions, or databases keep deserializing without intervention. When a legacy blob is loaded, the missing fields default to insensitive = true, strictNull = false, type = null.
Transformations¶
Phalcon\Support\Collection also exposes two transformation methods: toArray() and toJson(int $options). toArray() returns the object transformed as an array. This method returns the same array as jsonSerialize().
<?php
use Phalcon\Support\Collection;
$data = [
'colors' => [
'red',
'green',
'blue',
],
'year' => 1987,
];
$collection = new Collection($data);
print_r($collection->toArray()); // $data
toJson(int $options) returns a JSON representation of the object. It uses json_encode internally and accepts a parameter, which represents the flags that json_encode accepts. By default, the options bundle together a sensible escape set:
JSON_HEX_TAGJSON_HEX_APOSJSON_HEX_AMPJSON_HEX_QUOTJSON_UNESCAPED_SLASHESJSON_THROW_ON_ERROR
JSON_THROW_ON_ERROR is included so that encode failures (e.g., passing a value that cannot be JSON-encoded like a resource) raise an InvalidArgumentException rather than silently returning an empty string.
You can pass any valid flags to the method according to your needs.
<?php
use Phalcon\Support\Collection;
$data = [
'colors' => [
'red',
'green',
'blue',
],
'year' => 1987,
];
$collection = new Collection($data);
echo $collection->toJson();
// {"colors":["red","green","blue"],"year":1987}
echo $collection->toJson(JSON_PRETTY_PRINT);
/**
{
"colors": [
"red",
"green",
"blue"
],
"year": 1987
}
*/
Read Only Collection¶
Phalcon also offers a component that can be used in a read-only fashion. Phalcon\Support\Collection\ReadOnlyCollection can serve as a collection in your application that can only be populated with initial data but does not allow its contents to be changed throughout the application.
NOTE
This class has been renamed from ReadOnly in order to avoid collisions with PHP 8.x reserved words.
<?php
use Phalcon\Support\Collection\ReadOnlyCollection;
$data = [
'colors' => [
'red',
'green',
'blue',
],
'year' => 1987,
];
$collection = new ReadOnlyCollection($data);
echo $collection->toJson();
// {"colors":["red","green","blue"],"year":1987}
$collection->set('colors', ['red']); // Exception
Methods that would otherwise mutate state (clear, init, remove, replace, set) all throw Phalcon\Support\Collection\Exception. Read-only operations — get, has, keys, values, count, first, last, isEmpty, column, filter, map, reduce, sort, where, each, toArray, toJson — behave exactly as on a regular Collection.
Custom Objects¶
Phalcon allows developers to define their own collection objects. These objects must implement the canonical contract Phalcon\Contracts\Support\Collection. The expanded interface mirrors every public method exposed by Phalcon\Support\Collection:
<?php
namespace MyApp;
use Phalcon\Contracts\Support\Collection as CollectionContract;
class MyCollection implements CollectionContract
{
public function __get(string $element): mixed;
public function __isset(string $element): bool;
public function __set(string $element, mixed $value): void;
public function __unset(string $element): void;
public function clear(): void;
public function column(string $propertyOrMethod): array;
public function each(callable $callback): static;
public function filter(callable $callback): static;
public function first(): mixed;
public function get(
string $element,
mixed $defaultValue = null,
?string $cast = null
): mixed;
public function getKeys(bool $insensitive = true): array;
public function getType(): ?string;
public function getValues(): array;
public function has(string $element): bool;
public function init(array $data = []): void;
public function isEmpty(): bool;
public function keys(bool $insensitive = true): array;
public function last(): mixed;
public function map(callable $callback): static;
public function reduce(callable $callback, mixed $initial = null): mixed;
public function remove(string $element): void;
public function replace(array $data): void;
public function set(string $element, mixed $value): void;
public function sort(?callable $callback = null, int $order = SORT_ASC): static;
public function toArray(): array;
public function toJson(int $options = 4194383): string;
public function values(): array;
public function where(string $propertyOrMethod, mixed $value): static;
}
Interface location
The interface previously lived at Phalcon\Support\Collection\CollectionInterface. That symbol is retained as a deprecated alias that extends Phalcon\Contracts\Support\Collection, so existing implementations keep working without modification. New code should reference Phalcon\Contracts\Support\Collection directly.