inanepain / stdlib
Common classes that cover a wide range of cases that are used throughout the inanepain libraries.
Requires
- php: >=8.4
- ext-intl: *
- ext-simplexml: *
- psr/container: *
README
Table of Contents
inanepain/stdlib
Common classes that cover a wide range of cases that are used throughout the inanepain libraries.
1. Install
composercomposer require inanepain/stdlib
2. Output Strategy
The Output component provides a consistent strategy for converting data into
various formats. It is designed around the OutputInterface and an abstract
base class, allowing for easy expansion and uniform usage across the framework.
The Output tools are located in the Inane\Stdlib\Output namespace.
2.1. Components
-
OutputInterface— defines theoutput()method. -
AbstractOutput— base implementation handling input data storage and lazy-processing. -
ArrayOutput— converts input to a PHP array (supports JSON, Serialized, Objects). -
JsonStringOutput— converts input to a JSON string. -
SerializedOutput— converts input to a PHP serialized string. -
XmlOutput— converts input to aSimpleXMLElementobject. -
XmlStringOutput— converts input to an XML string.
2.2. API Overview
All output classes share the same constructor and method:
public function __construct(protected mixed $inputData); public function output(): mixed;
The output() method is lazy-loaded; the processing happens once and the result
is cached in the outputData property.
2.3. Usage
2.3.1. ArrayOutput
ArrayOutput is highly flexible. It attempts to detect the input type and convert
it to an array accordingly.
use Inane\Stdlib\Output\ArrayOutput; // From an object (recursive conversion) $output = new ArrayOutput($myObject); $array = $output->output(); // From a JSON string $output = new ArrayOutput('{"key": "value"}'); $array = $output->output(); // ['key' => 'value'] // From a serialized string $output = new ArrayOutput(serialize(['a' => 1])); $array = $output->output(); // ['a' => 1]
Conversion Logic (ArrayOutput)
-
If input is an array, it is returned as is.
-
If input is a string:
-
Tries to decode as JSON.
-
If not JSON, tries to unserialize.
-
If both fail, wraps the string in an array:
[$input].
-
-
If input is an object, it uses
iteratorToArrayDeepto convert it recursively. -
For any other type, it wraps the input in an array:
[$input].
2.3.2. JsonStringOutput
Converts any input into a JSON string using Inane\Stdlib\Json.
use Inane\Stdlib\Output\JsonStringOutput; $data = ['name' => 'Inane', 'type' => 'Framework']; $output = new JsonStringOutput($data); echo $output->output(); // {"name":"Inane","type":"Framework"}
2.3.3. SerializedOutput
Converts input into a PHP serialized string.
use Inane\Stdlib\Output\SerializedOutput; $output = new SerializedOutput(['a', 'b', 'c']); echo $output->output(); // a:3:{i:0;s:1:"a";i:1;s:1:"b";i:2;s:1:"c";}
2.3.4. XmlOutput
Converts input data into a SimpleXMLElement. It uses ArrayOutput internally
to normalize the input before conversion.
use Inane\Stdlib\Output\XmlOutput; $data = ['user' => ['id' => 1, 'name' => 'John']]; $output = new XmlOutput($data); $xml = $output->output(); // SimpleXMLElement instance
2.3.5. XmlStringOutput
Converts input data into a formatted XML string.
use Inane\Stdlib\Output\XmlStringOutput; $data = ['root' => ['item' => 'value']]; $output = new XmlStringOutput($data); echo $output->output(); /* <?xml version="1.0"?> <data><root><item>value</item></root></data> */
2.4. Extending
To create a new output format, extend AbstractOutput and implement the output() method:
use Inane\Stdlib\Output\AbstractOutput; class MyCustomOutput extends AbstractOutput { public function output(): string { if (!isset($this->outputData)) { // ... custom conversion logic ... $this->outputData = "processed data"; } return $this->outputData; } }
3. Merge
Helper utilities for merging configuration/options arrays and iterators with
explicit control over how keys are added and/or updated. The Merge tool lives
under Inane\Stdlib\Merge and consists of:
-
MergeTrait— core implementation and convenience helpers -
Merge— small class that exposes the trait as a ready‑to‑use type -
MergeInterface— contract for merge behaviour -
MergeMethod— enum that selects the merge strategy
3.1. When to use
Use Merge to combine option sets coming from defaults, environment, per‑user
overrides, feature flags, etc. It supports nested structures and works with
both PHP arrays and ArrayAccess/Iterator implementations.
3.2. Strategies (MergeMethod)
MergeMethod controls how keys are handled during a merge:
-
AddOnly— only add keys that do not exist on the target; existing keys are left unchanged. -
UpdateOnly(default) — only update keys that already exist on the target; new keys are ignored. -
AddAndUpdate— add missing keys and update existing keys (full overlay/recursive replace).
Merging is recursive for nested arrays/objects that are arrays or implement
ArrayAccess/Iterator on both source and target sides.
3.3. API overview
Namespace: Inane\Stdlib\Merge
Core static method:
Iterator|array MergeTrait::mergeOptionsWithMethod( MergeMethod $mergeMethod, Iterator|array $target, Iterator|array ...$sources ): Iterator|array
Convenience helpers (static):
-
mergeOptionsWithAddOnly($target, …$sources) -
mergeOptionsWithUpdateOnly($target, …$sources) -
mergeOptionsWithAddAndUpdate($target, …$sources)
Instance method (via Merge or any class using the trait):
public MergeMethod $mergeMethod = MergeMethod::UpdateOnly; // default public function mergeOptions(Iterator|array $target, Iterator|array ...$sources): Iterator|array
3.4. Usage
3.4.1. Static helpers
<?php use Inane\Stdlib\Merge\MergeTrait; // used via Merge facade below use Inane\Stdlib\Merge\Merge; $defaults = [ 'host' => 'localhost', 'port' => 3306, 'flags' => [ 'compress' => false, 'strict' => true ], ]; $env = [ 'port' => 3307, 'flags' => [ 'compress' => true ], 'extra' => 'ignored in UpdateOnly', ]; // Update existing keys only (default semantics) $merged = Merge::mergeOptionsUpdateOnly($defaults, $env); /* Result: [ 'host' => 'localhost', 'port' => 3307, 'flags' => [ 'compress' => true, 'strict' => true ], ] */ // Add missing keys only $added = Merge::mergeOptionsAddOnly($defaults, ['timeout' => 5]); // 'timeout' is appended, existing values untouched // Add and update (full overlay) $overlay = Merge::mergeOptionsAddAndUpdate($defaults, $env); // Includes 'extra' and applies nested updates
3.4.2. Instance with a configurable method
<?php use Inane\Stdlib\Merge\{Merge, MergeMethod}; $merger = new Merge(); $merger->mergeMethod = MergeMethod::AddAndUpdate; // choose strategy at runtime $target = [ 'a' => 1, 'b' => ['x' => true] ]; $source = [ 'b' => ['x' => false, 'y' => 2], 'c' => 3 ]; $result = $merger->mergeOptions($target, $source); // [ 'a' => 1, 'b' => ['x' => false, 'y' => 2], 'c' => 3 ]
3.5. Behavior details
-
The key existence on the target is determined as follows:
-
arrays:
array_key_exists($key, $target) -
ArrayAccess:$target→offsetExists($key) -
iterables:
isset($target[$key]) -
Recursion happens only when both source and target values at a key are array‑like (
is_arrayorArrayAccess). Otherwise, the source value replaces the target value subject to the chosen strategy. -
Multiple sources are merged left‑to‑right in the order provided.
3.6. Working with iterators and ArrayAccess
You can pass objects implementing Iterator and/or ArrayAccess as both target
and sources. Merge will respect their semantics for key existence checks and
assignments, allowing use with custom option containers.
3.7. Selecting a strategy dynamically
If you receive a user‑provided string (e.g. from config), you can map it to a
MergeMethod case using MergeMethod::tryFromName($name, $ignoreCase = false).
use Inane\Stdlib\Merge\MergeMethod; $method = MergeMethod::tryFromName('addonly', true) ?? MergeMethod::UpdateOnly;
3.8. JavaScript counterpart
For frontend experiments there is a simple ES module at
public/js/inane/class-lib/MergeOptions.mjs that mirrors the basic behaviour for merging option objects.
3.9. Tips
-
Use
UpdateOnlyto enforce a strict schema: only predefined keys get updated. -
Use
AddOnlyto apply safe defaults without overwriting user choices. -
Use
AddAndUpdatewhen you want a typical deep overlay of configuration.
4. VerifyValue
Utility class providing static methods for validating and verifying common value types such as booleans, emails, integers, floats, IP addresses, MAC addresses, domains, and regex-matched strings.
All methods wrap PHP’s native filter_var function with a consistent, expressive API and sensible defaults.
4.1. Methods
4.1.1. boolVerify
Validates and converts a given value into a boolean.
Accepts the same truthy/falsy strings that PHP’s filter_var recognises (e.g. "true", "yes", "1", "on" and their negatives).
public static function boolVerify(mixed $value, bool $nullOnFailure = false): ?boolTable 1. Parameters
| Parameter | Type | Description |
|---|---|---|
|
|
The value to validate and convert to boolean. |
|
|
When |
VerifyValue::boolVerify('yes'); // true VerifyValue::boolVerify('off'); // false VerifyValue::boolVerify('maybe', true); // null
4.1.2. emailVerify
Validates an email address or an array of email addresses.
When an array is supplied, each element is validated individually, and the method returns an associative array keyed by the original input values.
Signaturepublic static function emailVerify(string|array $value): false|string|arrayTable 2. Parameters
| Parameter | Type | Description |
|---|---|---|
|
|
A single email address string, or an array of email address strings. |
VerifyValue::emailVerify('user@example.com'); // 'user@example.com' VerifyValue::emailVerify('not-an-email'); // false VerifyValue::emailVerify(['a@b.com', 'bad', 'c@d.com']); // ['a@b.com' => 'a@b.com', 'bad' => false, 'c@d.com' => 'c@d.com']
4.1.3. integerVerify
Validates an integer value with optional range and base constraints.
Supports octal (prefix 0) and hexadecimal (prefix 0x) notation when the corresponding flags are enabled.
public static function integerVerify(mixed $int, mixed $default = false, ?int $min = null, ?int $max = null, bool $allowOctal = false, bool $allowHex = false): boolTable 3. Parameters
| Parameter | Type | Description |
|---|---|---|
|
|
The value to validate as an integer. |
|
|
Fallback value returned on validation failure. Pass |
|
|
Optional minimum allowed value (inclusive). |
|
|
Optional maximum allowed value (inclusive). |
|
|
When |
|
|
When |
VerifyValue::integerVerify(42); // true VerifyValue::integerVerify(42, false, 1, 100); // true VerifyValue::integerVerify(200, false, 1, 100); // false VerifyValue::integerVerify('0x1A', false, null, null, false, true); // true
4.1.4. intVerify
Validates an integer value using a named options array.
A convenience wrapper around integerVerify() that accepts a named options array instead of individual parameters. Unrecognised keys are silently ignored.
public static function intVerify(mixed $int, array $options = []): boolTable 4. Parameters
| Parameter | Type | Description |
|---|---|---|
|
|
The value to validate as an integer. |
|
|
Named validation options: |
VerifyValue::intVerify(42, ['min' => 1, 'max' => 100]); // true VerifyValue::intVerify('0xFF', ['allowHex' => true]); // true
4.1.5. floatVerify
Validates a float value with optional range and thousand-separator support.
Signaturepublic static function floatVerify(mixed $int, mixed $default = false, ?int $min = null, ?int $max = null, bool $acceptFloat = false): boolTable 5. Parameters
| Parameter | Type | Description |
|---|---|---|
|
|
The value to validate as a float. |
|
|
Fallback value returned on validation failure. Pass |
|
|
Optional minimum allowed value (inclusive). |
|
|
Optional maximum allowed value (inclusive). |
|
|
When |
VerifyValue::floatVerify(3.14); // true VerifyValue::floatVerify('1,234.56', false, null, null, true); // true VerifyValue::floatVerify('abc'); // false
4.1.6. regexVerify
Validates a value against a regular expression pattern.
Returns the original value when it matches the pattern, the $default string when provided and the match fails, or null otherwise.
public static function regexVerify(mixed $value, string $pattern, ?string $default = null): ?stringTable 6. Parameters
| Parameter | Type | Description |
|---|---|---|
|
|
The value to validate. |
|
|
A valid PCRE regular expression (including delimiters). |
|
|
Optional fallback string returned when validation fails. |
VerifyValue::regexVerify('hello123', '/^[a-z]+\d+$/'); // 'hello123' VerifyValue::regexVerify('!!!', '/^[a-z]+$/', 'no-match'); // 'no-match' VerifyValue::regexVerify('!!!', '/^[a-z]+$/'); // null
4.1.7. domainVerify
Validates a domain name, optionally enforcing strict hostname rules.
Signaturepublic static function domainVerify(mixed $value, bool $hostname = false): ?stringTable 7. Parameters
| Parameter | Type | Description |
|---|---|---|
|
|
The value to validate as a domain name. |
|
|
When |
VerifyValue::domainVerify('example.com'); // 'example.com' VerifyValue::domainVerify('-bad.com', true); // null VerifyValue::domainVerify('not a domain'); // null
4.1.8. ipVerify
Validates an IP address with configurable version and range policies.
By default, both IPv4 and IPv6 addresses are accepted. Passing false for one version while leaving the other as true restricts validation to the remaining version.
public static function ipVerify(mixed $value, bool $allowV4 = true, bool $allowV6 = true, bool $denyPrivate = false, bool $denyReserved = false, bool $globalOnly = false): ?stringTable 8. Parameters
| Parameter | Type | Description |
|---|---|---|
|
|
The value to validate as an IP address. |
|
|
Accept IPv4 addresses (default |
|
|
Accept IPv6 addresses (default |
|
|
Reject private-range addresses (e.g. |
|
|
Reject reserved-range addresses (e.g. |
|
|
Accept only globally routable addresses. |
VerifyValue::ipVerify('192.168.1.1'); // '192.168.1.1' VerifyValue::ipVerify('192.168.1.1', true, true, true); // null (private range denied) VerifyValue::ipVerify('::1', false, true); // '::1' (IPv6 only) VerifyValue::ipVerify('not-an-ip'); // null
4.1.9. macVerify
Validates a MAC address and optionally normalises its format.
PHP’s filter_var accepts colons (:), hyphens (-), and dots (.) as separators. When $normalize is true the validated address is stripped of its original separators and rebuilt using $separator.
public static function macVerify(mixed $value, bool $normalize = false, string $separator = ':'): ?stringTable 9. Parameters
| Parameter | Type | Description |
|---|---|---|
|
|
The value to validate as a MAC address. |
|
|
When |
|
|
The separator character used when normalising (default |
VerifyValue::macVerify('00-1A-2B-3C-4D-5E'); // '00-1A-2B-3C-4D-5E' VerifyValue::macVerify('00-1A-2B-3C-4D-5E', true); // '00:1a:2b:3c:4d:5e' VerifyValue::macVerify('00.1A.2B.3C.4D.5E', true, '-'); // '00-1a-2b-3c-4d-5e' VerifyValue::macVerify('not-a-mac'); // null
5. Website: github
github
██████████████ ██████████ ██ ████ ████ ██ ██ ██████████████
██ ██ ██ ████ ██████████ ██ ██ ██
██ ██████ ██ ████ ████ ████████ ██████████████████ ██ ██████ ██
██ ██████ ██ ████ ██ ████ ████████ ████ ██ ██████ ██
██ ██████ ██ ██ ██ ████ ██ ██ ██ ██████ ██
██ ██ ██ ██████ ██ ██ ██ ██ ██
██████████████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██████████████
██ ██████ ██ ██████████ ████
████ ████ ██ ████ ██ ██ ██ ██ ████ ██ ████
██ ████ ████ ████ ██ ██ ██ ██ ████ ██
████ ██████████ ██ ██ ██ ████ ████████ ██
████ ████████ ██ ████ ██ ████ ████ ████ ██
██ ████ ████ ████ ██ ████ ██ ██ ██ ████ ██ ████
██ ████ ████ ██████ ██ ██ ██ ████ ██ ██ ██
████ ██████████████ ██████ ██ ████████ ██ ████████
██ ██ ██ ██████ ██ ██ ████ ██ ██████ ██
████ ██████ ██ ██ ██ ████ ██ ██████ ██ ██ ██
██ ██████ ██ ██████ ████████ ██ ██ ██ ██
████ ████████ ████████████ ████████ ██████ ████ ██████ ████ ██
██ ██ ██ ████ ████ ████ ██ ████ ████ ██████████████ ██
██ ████████ ██ ██ ██ ██ ██████ ██ ██
██ ████████ ██ ██ ██████ ████ ██████ ████ ████ ██████
██ ████ ██ ██ ██ ██ ██ ██ ██████ ██
██ ██ ██ ████ ██ ██ ████ ██ ██ ██████ ██ ████████
██ ██████████ ████ ████ ██████ ██████████ ██████
██ ██ ██ ██ ██ ██ ██ ██ ████ ████ ██
████ ██ ██████ ████ ██████ ████ ████ ████ ████████ ████
██ ██████ ████ ██████ ██████████ ████ ████ ██ ██
██ ██████ ████ ██ ████ ██████████████ ████ ██████████████
██████ ████████ ██ ██ ██ ██ ██ ██████
██████████████ ██ ██████ ██████ ████ ████████ ██ ██ ██████ ██
██ ██ ██████ ████ ██ ██ ████ ████ ████
██ ██████ ██ ████ ██ ████ ████ ██ ██ ██████████████
██ ██████ ██ ██ ██████ ████ ██ ██ ██████ ████ ████
██ ██████ ██ ██ ██████████ ██ ████ ████ ████ ████
██ ██ ██ ██ ██ ██ ████ ██████ ████████
██████████████ ██ ██ ████ ██ ████ ██ ████ ██