ipl / stdlib
ipl Standard Library
Requires
- php: >=8.2
- ext-openssl: *
- evenement/evenement: ^3.0.1
- dev-main
- v0.15.0.x-dev
- v0.15.0
- v0.14.0
- v0.13.0
- v0.12.1
- v0.12.0
- v0.11.0
- v0.10.0
- v0.9.0
- v0.8.0
- v0.7.0
- v0.6.0
- v0.5.0
- v0.4.0
- v0.3.0
- v0.2.0
- v0.1.0
- dev-docs-and-repo-housekeeping
- dev-modernize-code
- dev-modernize-code-with-breaking-changes
- dev-add-option-attribute
- dev-exponential-backoff
- dev-strict-Translator-interface
- dev-update-filter-array-support
- dev-allow-to-use-cached-iterator
- dev-introduce-new-filter-rules
This package is auto-updated.
Last update: 2026-03-24 16:53:14 UTC
README
ipl/stdlib provides reusable building blocks for Icinga PHP libraries and
applications. It covers declarative filtering, event emission, string and
iterable utilities, lightweight data and message containers, and a
stable priority queue.
Installation
The recommended way to install this library is via Composer:
composer require ipl/stdlib
ipl/stdlib requires PHP 8.2 or later with the openssl extension.
Usage
Filter Rows With Declarative Rules
Build composable filter trees with ipl\Stdlib\Filter and evaluate them
against arrays or objects:
use ipl\Stdlib\Filter; $filter = Filter::all( Filter::equal('problem', '1'), Filter::none(Filter::equal('handled', '1')), Filter::like('service', 'www.*') ); $row = [ 'problem' => '1', 'handled' => '0', 'service' => 'www.icinga.com', ]; if (Filter::match($filter, $row)) { // The row matches the rule set. }
Available condition factories: equal, unequal, like, unlike,
greaterThan, greaterThanOrEqual, lessThan, lessThanOrEqual.
Available logical factories: all, any, none, not.
Build Filters Incrementally
When an object needs to collect filter conditions over time, use the Filters
trait. It complements the Filterable contract and exposes filter(),
orFilter(), notFilter(), and orNotFilter():
use ipl\Stdlib\Contract\Filterable; use ipl\Stdlib\Filter; use ipl\Stdlib\Filters; class Query implements Filterable { use Filters; } $query = (new Query()) ->filter(Filter::equal('problem', '1')) ->orNotFilter(Filter::equal('handled', '1')); $filter = $query->getFilter();
Events
The Events trait wraps Evenement and
adds event validation. Declare event name constants on the class to give
callers a typo-safe API and to let isValidEvent() enforce an explicit
allow-list:
use ipl\Stdlib\Events; class Connection { use Events; public const ON_CONNECT = 'connected'; public const ON_DISCONNECT = 'disconnected'; protected function isValidEvent($event): bool { return in_array($event, [static::ON_CONNECT, static::ON_DISCONNECT], true); } public function open(): void { // ... connect ... $this->emit(self::ON_CONNECT, [$this]); } public function close(): void { // ... disconnect ... $this->emit(self::ON_DISCONNECT, [$this]); } } $conn = new Connection(); $conn->on(Connection::ON_CONNECT, function (Connection $c): void { echo "Connected\n"; }); $conn->on(Connection::ON_DISCONNECT, function (Connection $c): void { echo "Disconnected\n"; }); $conn->open(); $conn->close();
Utility Helpers
Str
Str offers string utilities that complement PHP's built-in functions.
It converts between naming conventions, splits and trims in one step, and
provides startsWith with case-insensitive matching.
use ipl\Stdlib\Str; // Convert snake_case or kebab-case identifiers to camelCase: Str::camel('host_name'); // 'hostName' Str::camel('display-name'); // 'displayName' // Split on a delimiter and trim whitespace from every part in one pass: Str::trimSplit(' foo , bar , baz '); // ['foo', 'bar', 'baz'] Str::trimSplit('root:secret', ':'); // ['root', 'secret'] // Always return exactly $limit parts: pads with null if the delimiter is // absent, and fold any remainder into the last part if there are more // separators than expected: [$user, $pass] = Str::symmetricSplit('root', ':', 2); // ['root', null] [$user, $pass] = Str::symmetricSplit('root:secret:extra', ':', 2); // ['root', 'secret:extra'] // Case-insensitive prefix check: Str::startsWith('Foobar', 'foo', caseSensitive: false); // true Str::startsWith('foobar', 'foo'); // true
Seq
Seq searches arrays, iterators, and generators by value, key, or callback
without first materializing them into arrays. When the second argument to
find or contains is a non-callable, it is compared by value; pass a
closure to match by predicate instead:
use ipl\Stdlib\Seq; $users = [ 'alice' => 'admin', 'bob' => 'viewer', ]; Seq::contains($users, 'viewer'); // true [$key, $value] = Seq::find($users, 'admin'); // ['alice', 'admin'] // Match by predicate — returns as soon as a result is found: [$key, $value] = Seq::find($users, fn(string $role): bool => $role !== 'admin'); // ['bob', 'viewer']
Iterable Helpers
use function ipl\Stdlib\iterable_key_first; use function ipl\Stdlib\iterable_value_first; $map = [ 'id' => 42, 'name' => 'Alice', ]; iterable_key_first($map); // 'id' iterable_value_first($map); // 42 // Works with generators and iterators — does not require an array: iterable_key_first(new ArrayIterator(['a' => 1])); // 'a' iterable_key_first([]); // null
Grouping With yield_groups
yield_groups partitions a pre-sorted traversable into named groups.
The callback must return at least the grouping criterion, but it can
also return a custom value and key. The traversable must be sorted
by the grouping criterion before being passed in; results are undefined
otherwise:
use function ipl\Stdlib\yield_groups; foreach (yield_groups($rows, fn(object $row): string => $row->category) as $category => $items) { // $items contains all rows for $category. }
Other Utility Classes
Data— mutable key/value storeMessages— collects user-facing messages and supportssprintf-style placeholdersPriorityQueue— extendsSplPriorityQueuewith stable insertion-order for items at equal priority; iterate non-destructively withyieldAll()
Changelog
See CHANGELOG.md for a list of notable changes.
License
ipl/stdlib is licensed under the terms of the MIT License.