1. Go to this page and download the library: Download inanepain/stdlib library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
inanepain / stdlib example snippets
declare(strict_types=1);
use Inane\Stdlib\Bitmask\BitmaskEnumTrait;
enum Permission: int {
use BitmaskEnumTrait;
case Read = 1 << 0; // 1
case Write = 1 << 1; // 2
case Execute = 1 << 2; // 4
case Delete = 1 << 3; // 8
}
// Build a mask from multiple flags
$mask = Permission::combine(Permission::Read, Permission::Write); // 3
// Normalise input
$mask = Permission::parseBitmask($mask); // still 3
// Check across the enum
$hasAny = Permission::hasAny($mask); // true (at least one flag set)
$hasAll = Permission::hasAll($mask); // false (not all flags set)
// Check a specific flag
$canRead = Permission::has($mask, Permission::Read); // true
$canExec = Permission::has($mask, Permission::Execute); // false
// The same checks via instance helpers
$canRead2 = Permission::Read->in($mask); // true
$canExec2 = Permission::Execute->in($mask); // false
// Modify mask
$mask = Permission::add($mask, Permission::Delete); // add Delete
$mask = Permission::Write->removeFrom($mask); // remove Write
// List set flags
$set = Permission::list($mask); // [Permission::Read, Permission::Delete]
----
== Tips
- When defining new flags, always shift from 0 upwards (`1 << n`) and avoid overlapping values.
- Store masks as integers in persistence layers. The trait makes converting to/from cases trivial.
:leveloffset!:
<<<
:leveloffset: +1
= 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.
== Components
- `OutputInterface` — defines the `output()` method.
- `AbstractOutput` — base implementation handling input data storage and lazy-processing.
- `ArrayOutput` — converts input to a PHP array (supports JSON, Serialized, Objects).
- `ArrayStringShortSyntaxOutput` — converts input to a PHP short array syntax string.
- `JsonStringOutput` — converts input to a JSON string.
- `SerializedOutput` — converts input to a PHP serialized string.
- `XmlOutput` — converts input to a `SimpleXMLElement` object.
- `XmlStringOutput` — converts input to an XML string.
== API Overview
All output classes share the same constructor and method:
[source,php]
----
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.
== Usage
=== ArrayOutput
`ArrayOutput` is highly flexible. It attempts to detect the input type and convert
it to an array accordingly.
[source,php]
----
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)
1. If input is an **array**, it is returned as is.
2. 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]`.
3. If input is an **object**, it uses `iteratorToArrayDeep` to convert it recursively.
4. For any other type, it wraps the input in an array: `[$input]`.
=== JsonStringOutput
Converts any input into a JSON string using `Inane\Stdlib\Json`.
[source,php]
----
use Inane\Stdlib\Output\JsonStringOutput;
$data = ['name' => 'Inane', 'type' => 'Framework'];
$output = new JsonStringOutput($data);
echo $output->output(); // {"name":"Inane","type":"Framework"}
----
=== SerializedOutput
Converts input into a PHP serialized string.
[source,php]
----
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";}
----
=== ArrayStringShortSyntaxOutput
Converts input data into a PHP short array syntax string (`[]`). It first uses
`ArrayOutput` to normalise input into an array, then transforms the result to
short syntax.
[source,php]
----
use Inane\Stdlib\Output\ArrayStringShortSyntaxOutput;
$data = ['name' => 'Ada', 'count' => 2];
$output = new ArrayStringShortSyntaxOutput($data);
echo $output->output();
/*
[
'name' => 'Ada',
'count' => 2,
]
*/
----
=== XmlOutput
Converts input data into a `SimpleXMLElement`. It uses `ArrayOutput` internally
to normalise the input before conversion.
[source,php]
----
use Inane\Stdlib\Output\XmlOutput;
$data = ['user' => ['id' => 1, 'name' => 'John']];
$output = new XmlOutput($data);
$xml = $output->output(); // SimpleXMLElement instance
----
=== XmlStringOutput
Converts input data into a formatted XML string.
[source,php]
----
use Inane\Stdlib\Output\XmlStringOutput;
$data = ['root' => ['item' => 'value']];
$output = new XmlStringOutput($data);
echo $output->output();
/*
<?xml version="1.0"
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 ]
----
== Behaviour 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_array` or `ArrayAccess`). Otherwise, the source value replaces the target value
subject to the chosen strategy.
- Multiple sources are merged left‑to‑right in the order provided.
== 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.
== 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)`.
[source,php]
----
use Inane\Stdlib\Merge\MergeMethod;
$method = MergeMethod::tryFromName('addonly', true) ?? MergeMethod::UpdateOnly;
----
== JavaScript counterpart
For frontend experiments there’s a simple ES module at
`public/js/inane/class-lib/MergeOptions.mjs` that mirrors the basic behaviour for merging option objects.
== Tips
- Use `UpdateOnly` to enforce a strict schema: only predefined keys get updated.
- Use `AddOnly` to apply safe defaults without overwriting user choices.
- Use `AddAndUpdate` when you want a typical deep overlay of configuration.
:leveloffset!:
<<<
:leveloffset: +1
= Value
Classes that verify or sanitise values. Mostly using `filter_var`.
:leveloffset: +1
= Verify Value
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.
== Methods
=== 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).
.Signature
[source,php]
----
public static function boolVerify(mixed $value, bool $nullOnFailure = false): ?bool
----
.Parameters
[cols="1,1,3"]
|===
|Parameter |Type |Description
|`$value`
|`mixed`
|The value to validate and convert to boolean.
|`$nullOnFailure`
|`bool`
|When `true`, returns `null` on failure instead of `false`.
|===
.Returns: `bool\|null` — The boolean result or `null` when conversion fails and `$nullOnFailure` is `true`.
.Example
[source,php]
----
VerifyValue::boolVerify('yes'); // true
VerifyValue::boolVerify('off'); // false
VerifyValue::boolVerify('maybe', true); // null
----
=== alphaVerify
Validates an alphabetic string.
.Signature
[source,php]
----
public static function alphaVerify(string $value): false|string
----
.Parameters
[cols="1,1,3"]
|===
|Parameter |Type |Description
|`$value`
|`string`
|The value to validate.
|===
.Returns: `false\|string` — The original value when alphabetic; otherwise, `false`.
.Example
[source,php]
----
VerifyValue::alphaVerify('Hello'); // 'Hello'
VerifyValue::alphaVerify('Hello123'); // false
----
=== digitVerify
Validates a value containing only decimal digits.
.Signature
[source,php]
----
public static function digitVerify(mixed $value): mixed
----
.Parameters
[cols="1,1,3"]
|===
|Parameter |Type |Description
|`$value`
|`mixed`
|The value to validate.
|===
.Returns: `mixed` — The original value when it contains only decimal digits; otherwise, `false`.
.Example
[source,php]
----
VerifyValue::digitVerify('12345'); // '12345'
VerifyValue::digitVerify('12.45'); // false
----
=== xdigitVerify
Validates a value containing only hexadecimal digits.
.Signature
[source,php]
----
public static function xdigitVerify(mixed $value): mixed
----
.Parameters
[cols="1,1,3"]
|===
|Parameter |Type |Description
|`$value`
|`mixed`
|The value to validate.
|===
.Returns: `mixed` — The original value when it contains only hexadecimal digits; otherwise, `false`.
.Example
[source,php]
----
VerifyValue::xdigitVerify('1A2b3C'); // '1A2b3C'
VerifyValue::xdigitVerify('0x1A'); // false
----
=== alphaNumericVerify
Validates an alphanumeric string.
.Signature
[source,php]
----
public static function alphaNumericVerify(string $value): false|string
----
.Parameters
[cols="1,1,3"]
|===
|Parameter |Type |Description
|`$value`
|`string`
|The value to validate.
|===
.Returns: `false\|string` — The original value when alphanumeric; otherwise, `false`.
.Example
[source,php]
----
VerifyValue::alphaNumericVerify('abc123'); // 'abc123'
VerifyValue::alphaNumericVerify('abc 123'); // false
----
=== 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.
.Signature
[source,php]
----
public static function emailVerify(string|array $value): false|string|array
----
.Parameters
[cols="1,1,3"]
|===
|Parameter |Type |Description
|`$value`
|`string\|array`
|A single email address string, or an array of email address strings.
|===
.Returns: `false\|string\|array` — The validated email string, an associative array of results for array input or `false` if a single address fails validation.
.Example
[source,php]
----
VerifyValue::emailVerify('[email protected]'); // '[email protected]'
VerifyValue::emailVerify('not-an-email'); // false
VerifyValue::emailVerify(['[email protected]', 'bad', '[email protected]']); // ['[email protected]' => '[email protected]', 'bad' => false, '[email protected]' => '[email protected]']
----
=== 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.
.Signature
[source,php]
----
public static function integerVerify(mixed $int, mixed $default = false, ?int $min = null, ?int $max = null, bool $allowOctal = false, bool $allowHex = false): bool
----
.Parameters
[cols="1,1,3"]
|===
|Parameter |Type |Description
|`$int`
|`mixed`
|The value to validate as an integer.
|`$default`
|`mixed`
|Fallback value returned on validation failure. Pass `false` to omit.
|`$min`
|`int\|null`
|Optional minimum allowed value (inclusive).
|`$max`
|`int\|null`
|Optional maximum allowed value (inclusive).
|`$allowOctal`
|`bool`
|When `true`, octal notation is accepted.
|`$allowHex`
|`bool`
|When `true`, hexadecimal notation is accepted.
|===
.Returns: `bool` — `true` when the value passes integer validation, `false` otherwise.
.Example
[source,php]
----
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
----
=== intVerify
Validates an integer value using an option array.
A convenience wrapper around `integerVerify()` that accepts a named options array instead of individual parameters. Unrecognised keys are silently ignored.
.Signature
[source,php]
----
public static function intVerify(mixed $int, array $options = []): bool
----
.Parameters
[cols="1,1,3"]
|===
|Parameter |Type |Description
|`$int`
|`mixed`
|The value to validate as an integer.
|`$options`
|`array`
|Named validation options: `default`, `min`, `max`, `allowOctal`, `allowHex`.
|===
.Returns: `bool` — `true` when the value passes integer validation, `false` otherwise.
.Example
[source,php]
----
VerifyValue::intVerify(42, ['min' => 1, 'max' => 100]); // true
VerifyValue::intVerify('0xFF', ['allowHex' => true]); // true
----
=== floatVerify
Validates a float value with optional range and thousand-separator support.
.Signature
[source,php]
----
public static function floatVerify(mixed $int, mixed $default = false, ?int $min = null, ?int $max = null, bool $acceptFloat = false): bool
----
.Parameters
[cols="1,1,3"]
|===
|Parameter |Type |Description
|`$int`
|`mixed`
|The value to validate as a float.
|`$default`
|`mixed`
|Fallback value returned on validation failure. Pass `false` to omit.
|`$min`
|`int\|null`
|Optional minimum allowed value (inclusive).
|`$max`
|`int\|null`
|Optional maximum allowed value (inclusive).
|`$acceptFloat`
|`bool`
|When `true`, values containing a thousand separator (`,`) are accepted.
|===
.Returns: `bool` — `true` when the value passes float validation, `false` otherwise.
.Example
[source,php]
----
VerifyValue::floatVerify(3.14); // true
VerifyValue::floatVerify('1,234.56', false, null, null, true); // true
VerifyValue::floatVerify('abc'); // false
----
=== 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.
.Signature
[source,php]
----
public static function regexVerify(mixed $value, string $pattern, ?string $default = null): ?string
----
.Parameters
[cols="1,1,3"]
|===
|Parameter |Type |Description
|`$value`
|`mixed`
|The value to validate.
|`$pattern`
|`string`
|A valid PCRE regular expression (including delimiters).
|`$default`
|`string\|null`
|Optional fallback string returned when validation fails.
|===
.Returns: `string\|null` — The matched value, the default fallback or `null` on failure.
.Example
[source,php]
----
VerifyValue::regexVerify('hello123', '/^[a-z]+\d+$/'); // 'hello123'
VerifyValue::regexVerify('!!!', '/^[a-z]+$/', 'no-match'); // 'no-match'
VerifyValue::regexVerify('!!!', '/^[a-z]+$/'); // null
----
=== domainVerify
Validates a domain name, optionally enforcing strict hostname rules.
.Signature
[source,php]
----
public static function domainVerify(mixed $value, bool $hostname = false): ?string
----
.Parameters
[cols="1,1,3"]
|===
|Parameter |Type |Description
|`$value`
|`mixed`
|The value to validate as a domain name.
|`$hostname`
|`bool`
|When `true`, applies stricter hostname validation rules.
|===
.Returns: `string\|null` — The validated domain string or `null` if validation fails.
.Example
[source,php]
----
VerifyValue::domainVerify('example.com'); // 'example.com'
VerifyValue::domainVerify('-bad.com', true); // null
VerifyValue::domainVerify('not a domain'); // null
----
=== 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.
.Signature
[source,php]
----
public static function ipVerify(mixed $value, bool $allowV4 = true, bool $allowV6 = true, bool $denyPrivate = false, bool $denyReserved = false, bool $globalOnly = false): ?string
----
.Parameters
[cols="1,1,3"]
|===
|Parameter |Type |Description
|`$value`
|`mixed`
|The value to validate as an IP address.
|`$allowV4`
|`bool`
|Accept IPv4 addresses (default `true`).
|`$allowV6`
|`bool`
|Accept IPv6 addresses (default `true`).
|`$denyPrivate`
|`bool`
|Reject private-range addresses (e.g. `192.168.x.x`).
|`$denyReserved`
|`bool`
|Reject reserved-range addresses (e.g. `0.0.0.0`).
|`$globalOnly`
|`bool`
|Accept only globally routable addresses.
|===
.Returns: `string\|null` — The validated IP address string or `null` if validation fails.
.Example
[source,php]
----
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
----
=== macVerify
Validates a MAC address and optionally normalises its format.
PHP's `filter_var` accepts colons (`:`), hyphens (`-`), and dots (`.`) as separators. When `$normalise` is `true`, the validated address is stripped of its original separators and rebuilt using `$separator`.
.Signature
[source,php]
----
public static function macVerify(mixed $value, bool $normalise = false, string $separator = ':'): ?string
----
.Parameters
[cols="1,1,3"]
|===
|Parameter |Type |Description
|`$value`
|`mixed`
|The value to validate as a MAC address.
|`$normalise`
|`bool`
|When `true`, the returned address is normalised to a consistent separator.
|`$separator`
|`string`
|The separator character used when normalising (default `:`).
|===
.Returns: `string\|null` — The validated (and optionally normalised) MAC address or `null` if validation fails.
.Example
[source,php]
----
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
----
:leveloffset: 1
<<<
:leveloffset: +1
= Sanitise Value
Utility class providing static methods for sanitising common value types such as strings containing markup, emails, URLs, integers and floats.
Most methods wrap PHP's native `filter_var` function with a consistent, expressive API and sensible defaults. Each method accepts either a single value or an array of values.
== Methods
=== stripTags
Removes HTML and PHP tags from a string or each string in an array.
.Signature
[source,php]
----
public static function stripTags(string|array $string, array|string|null $allowedTags = null): string|array
----
.Parameters
[cols="1,1,3"]
|===
|Parameter |Type |Description
|`$string`
|`string\|array`
|The value to sanitise.
|`$allowedTags`
|`array\|string\|null`
|Tags permitted in the result.
|===
.Returns: `string\|array` — The sanitised value.
.Example
[source,php]
----
SanitiseValue::stripTags('<p>Hello <b>World</b></p>'); // 'Hello World'
SanitiseValue::stripTags('<p>Hello <b>World</b></p>', '<b>'); // 'Hello <b>World</b>'
SanitiseValue::stripTags(['<i>a</i>', '<i>b</i>']); // ['a', 'b']
----
=== emailSanitise
Sanitises an email address or each address in an array.
.Signature
[source,php]
----
public static function emailSanitise(string|array $value, bool $stripTags = false): false|string|array
----
.Parameters
[cols="1,1,3"]
|===
|Parameter |Type |Description
|`$value`
|`string\|array`
|The email address or addresses to sanitise.
|`$stripTags`
|`bool`
|Whether to remove tags before sanitising.
|===
.Returns: `false\|string\|array` — The sanitised email value or values.
.Example
[source,php]
----
SanitiseValue::emailSanitise('us(er)@example.com'); // '[email protected]'
SanitiseValue::emailSanitise('<b>user</b>@example.com', true); // '[email protected]'
SanitiseValue::emailSanitise(['a [email protected]', '[email protected]']); // ['[email protected]', '[email protected]']
----
=== urlSanitise
Sanitises a URL or each URL in an array.
.Signature
[source,php]
----
public static function urlSanitise(string|array $value, bool $stripTags = false): false|string|array
----
.Parameters
[cols="1,1,3"]
|===
|Parameter |Type |Description
|`$value`
|`string\|array`
|The URL or URLs to sanitise.
|`$stripTags`
|`bool`
|Whether to remove tags before sanitising.
|===
.Returns: `false\|string\|array` — The sanitised URL value or values.
.Example
[source,php]
----
SanitiseValue::urlSanitise('http://exa mple.com/pa th'); // 'http://example.com/path'
SanitiseValue::urlSanitise('<b>http://example.com</b>', true); // 'http://example.com'
----
=== intSanitise
Sanitises an integer value or each value in an array by removing all characters except digits, plus and minus signs.
.Signature
[source,php]
----
public static function intSanitise(int|float|string|array $value): false|int|array
----
.Parameters
[cols="1,1,3"]
|===
|Parameter |Type |Description
|`$value`
|`int\|float\|string\|array`
|The value or values to sanitise.
|===
.Returns: `false\|int\|array` — The sanitised integer value or values.
.Example
[source,php]
----
SanitiseValue::intSanitise('R 1 234.56'); // '123456'
SanitiseValue::intSanitise('-42abc'); // '-42'
SanitiseValue::intSanitise(['1a', '2b']); // ['1', '2']
----
=== floatSanitise
Sanitises a floating-point value or each value in an array.
By default, all characters except digits, plus and minus signs are removed. The optional flags retain decimal separators, thousand separators and scientific notation respectively.
.Signature
[source,php]
----
public static function floatSanitise(int|float|string|array $value, bool $allowFraction = false, bool $allowThousand = false, bool $allowScientific = false): false|float|array
----
.Parameters
[cols="1,1,3"]
|===
|Parameter |Type |Description
|`$value`
|`int\|float\|string\|array`
|The value or values to sanitise.
|`$allowFraction`
|`bool`
|Whether to retain decimal separators.
|`$allowThousand`
|`bool`
|Whether to retain thousand separators.
|`$allowScientific`
|`bool`
|Whether to retain scientific notation.
|===
.Returns: `false\|float\|array` — The sanitised floating-point value or values.
.Example
[source,php]
----
SanitiseValue::floatSanitise('R 1,234.56'); // '123456'
SanitiseValue::floatSanitise('R 1,234.56', true); // '1234.56'
SanitiseValue::floatSanitise('R 1,234.56', true, true); // '1,234.56'
SanitiseValue::floatSanitise('1.2e3', true, false, true); // '1.2e3'
----
:leveloffset: 1
:leveloffset!:
<<<
:leveloffset: +1
= FuzzyTime
This section documents the `FuzzyTimeTrait` used to express a point in time the way a person would say it out loud.
== Overview
`FuzzyTimeTrait` converts a time into a spoken-style English phrase such as `quarter past nine`. It provides:
* Rounding of minutes to the nearest five minutes
* `past` phrasing up to and including half past the hour
* `to` phrasing with the following hour after half past
* Hour roll-over when the rounded minutes reach sixty
Trait location:
* Namespace: `Inane\Stdlib\Parser`
* File: `lib/inanepain/stdlib/src/Parser/FuzzyTimeTrait.php`
== Requirements and conventions
* Use on any class that needs fuzzy time wording; the API is static, so no state is added.
* Accepted input is a `DateTime`, an `Inane\Datetime\Timestamp`, or `null` for the current time.
* Output is a twelve-hour phrase without a meridiem indicator: `one o'clock` covers both 01:00 and 13:00.
== API
Static helper on the class using the trait:
* `fuzzyClock(null|\DateTime|Timestamp $time = null): string` — Returns the time in words, defaulting to now.
NOTE: `numToWords()` it’s an internal helper and isn’t part of the public API.
== Example: Time in words
[source,php]
----
declare(strict_types=1);
use Inane\Stdlib\Parser\FuzzyTimeTrait;
final class Clock {
use FuzzyTimeTrait;
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.