Page MenuHomeDevCentral

D2810.id10636.diff
No OneTemporary

D2810.id10636.diff

diff --git a/.gitignore b/.gitignore
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@
# Caches
.phpunit.result.cache
.phpunit.cache/
+*/doc/cache/
diff --git a/omnitools/.phan/config.php b/omnitools/.phan/config.php
--- a/omnitools/.phan/config.php
+++ b/omnitools/.phan/config.php
@@ -4,7 +4,7 @@
return [
- 'target_php_version' => '7.2',
+ 'target_php_version' => '8.1',
// If enabled, missing properties will be created when
// they are first seen. If false, we'll report an
diff --git a/omnitools/doc/Makefile b/omnitools/doc/Makefile
new file mode 100644
--- /dev/null
+++ b/omnitools/doc/Makefile
@@ -0,0 +1,29 @@
+# -------------------------------------------------------------
+# Keruald OmniTools documentation
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# Project: Keruald
+# Description: Build documentation
+# License: Trivial work, not eligible to copyright
+# -------------------------------------------------------------
+
+MKDIR=mkdir -p
+RMDIR=rm -rf
+
+TARGET ?= dist
+
+all: doc
+
+doc: doc-base doc-enrich
+
+doc-base: ${TARGET}/index.html
+doc-enrich: ${TARGET}/.enriched
+
+${TARGET}/index.html:
+ $(MKDIR) $(TARGET)
+ doctum update doctum.php
+
+${TARGET}/.enriched:
+ ./enrich.py && touch $(TARGET)/.enriched
+
+clean:
+ ${RMDIR} ${TARGET}
diff --git a/omnitools/doc/README.md b/omnitools/doc/README.md
new file mode 100644
--- /dev/null
+++ b/omnitools/doc/README.md
@@ -0,0 +1,15 @@
+## Keruald OmniTools documentation
+
+### Build the documentation
+
+To build the documentation, you need make and Doctum installed.
+
+Then run `make`.
+
+The continuous delivery (CD) infrastucture uses this directory to do so.
+
+### Directory structure
+
+* `doctum.php`: configuration file for Doctum
+* `Makefile`: instructions to build the documentation
+* `_blocks/`: blocks to enrich documentation after Doctum has generated it.
diff --git a/omnitools/doc/_blocks/global-ns.html b/omnitools/doc/_blocks/global-ns.html
new file mode 100644
--- /dev/null
+++ b/omnitools/doc/_blocks/global-ns.html
@@ -0,0 +1,6 @@
+ <h2>How to enable those functions?</h2>
+ <p>By default, those functions ARE NOT registered in the global namespace.</p>
+ <p>If you wish to ease debug and have them available, you need to
+ <a href="Keruald/OmniTools/Debug/Debugger.html#method_register">register them</a> by calling
+ <code>Keruald\OmniTools\Debug\Debugger::register()</code>
+ </p>
diff --git a/omnitools/doc/doctum.php b/omnitools/doc/doctum.php
new file mode 100644
--- /dev/null
+++ b/omnitools/doc/doctum.php
@@ -0,0 +1,22 @@
+<?php
+
+use Doctum\Doctum;
+use Symfony\Component\Finder\Finder;
+
+$iterator = Finder::create()
+ ->files()
+ ->name("*.php")
+ ->in("../src");
+
+$options = [
+ "title" => "Keruald OmniTools",
+ "build_dir" => "/srv/doc/keruald/omnitools",
+ "footer_link" => [
+ "before_text" => "[ Keruald | ",
+ "href" => "https://devcentral.nasqueron.org/u/keruald",
+ "link_text" => "Project dashboard",
+ "after_text" => " | License: BSD-2-Clause ]",
+ ],
+];
+
+return new Doctum($iterator, $options);
diff --git a/omnitools/doc/enrich.py b/omnitools/doc/enrich.py
new file mode 100755
--- /dev/null
+++ b/omnitools/doc/enrich.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python3
+
+# -------------------------------------------------------------
+# Enrich documentation
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# Project: Keruald
+# Description: Add _blocks to the Doctum generated documentation.
+# License: Trivial work, not eligible to copyright
+# -------------------------------------------------------------
+
+
+import os
+import sys
+
+
+# -------------------------------------------------------------
+# Documentation enrichment helper methods
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+
+def add_html_block(target_path, source_block_path, before):
+ with open(source_block_path, "r") as fd:
+ block_content = fd.read()
+
+ with open(target_path, "r") as fd:
+ target_content = fd.read()
+
+ pos = target_content.find(before)
+ if pos == -1:
+ raise RuntimeError("Can't find expression in target path: " + before)
+
+ with open(target_path, "w") as fd:
+ fd.write(target_content[0:pos])
+ fd.write(block_content)
+ fd.write(target_content[pos:])
+
+
+# -------------------------------------------------------------
+# Documentation enrichment tasks
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+
+def enrich_global_ns(target_path, source_block_path):
+ add_html_block(target_path, source_block_path, '</div><div id="footer">')
+
+
+# -------------------------------------------------------------
+# Application entry point
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+
+def run(doc_path):
+ enrich_global_ns(f"{doc_path}/[Global_Namespace].html", "_blocks/global-ns.html")
+
+
+if __name__ == "__main__":
+ try:
+ target = os.environ["TARGET"]
+ except KeyError:
+ print("TARGET environment variable isn't defined.", file=sys.stderr)
+ sys.exit(1)
+ run(target)
diff --git a/omnitools/src/Collections/ArrayUtilities.php b/omnitools/src/Collections/ArrayUtilities.php
--- a/omnitools/src/Collections/ArrayUtilities.php
+++ b/omnitools/src/Collections/ArrayUtilities.php
@@ -5,6 +5,9 @@
use Closure;
+/**
+ * Callback methods and facades to use directly the methods with arrays.
+ */
class ArrayUtilities {
///
@@ -12,6 +15,9 @@
///
/**
+ * Cast the elements of an array to integers.
+ *
+ * @param array $array An array with elements to cast to integers
* @return int[]
*/
public static function toIntegers (array $array) : array {
@@ -24,6 +30,11 @@
/// Helpers to get callbacks for array_walk methods
///
+ /**
+ * Callback method to cast elements into integers.
+ *
+ * @return Closure
+ */
public static function toIntegerCallback () : Closure {
return function (&$item) {
$item = (int)$item;
diff --git a/omnitools/src/Collections/BaseCollection.php b/omnitools/src/Collections/BaseCollection.php
--- a/omnitools/src/Collections/BaseCollection.php
+++ b/omnitools/src/Collections/BaseCollection.php
@@ -3,6 +3,9 @@
namespace Keruald\OmniTools\Collections;
+/**
+ * Abstract base class to represent collections like vectors or maps.
+ */
abstract class BaseCollection {
use WithCollection;
@@ -11,6 +14,13 @@
/// Constructors
///
+ /**
+ * Create a new collection instance from the specified iterable.
+ *
+ * @param iterable $items The elements to put in the new collection
+ *
+ * @return static The collection with the elements from the iterable
+ */
public static abstract function from (iterable $items) : static;
///
@@ -23,14 +33,29 @@
/// Getters
///
+ /**
+ * Convert the collection into a PHP array.
+ *
+ * @return array A PHP array representing the collection
+ */
public abstract function toArray () : array;
///
/// Properties
///
+ /**
+ * Count how many elements a collection has.
+ *
+ * @return int The number of elements
+ */
public abstract function count () : int;
+ /**
+ * Determine if a collection is empty.
+ *
+ * @return bool true if the collection has 0 element; if not, false.
+ */
public abstract function isEmpty () : bool;
}
diff --git a/omnitools/src/Collections/BaseMap.php b/omnitools/src/Collections/BaseMap.php
--- a/omnitools/src/Collections/BaseMap.php
+++ b/omnitools/src/Collections/BaseMap.php
@@ -5,6 +5,12 @@
use ArrayAccess;
use IteratorAggregate;
+/**
+ * Abstract base class to represent hashmaps / associative arrays / dictionaries.
+ *
+ * It also provides a concrete implementation for ArrayAccess interface.
+ *
+ */
abstract class BaseMap extends BaseCollection
implements ArrayAccess, IteratorAggregate {
@@ -12,16 +18,62 @@
/// Methods to implement
///
+ /**
+ * Get the value at the specified key.
+ *
+ * @param mixed $key The key
+ *
+ * @return mixed The value
+ */
public abstract function get (mixed $key) : mixed;
+ /**
+ * Get the value at the specified key.
+ *
+ * @param mixed $key The key
+ * @param mixed $defaultValue The value to return if the key doesn't exist.
+ *
+ * @return mixed When the key exists, the value at that key; otherwise, the default value
+ */
public abstract function getOr (mixed $key, mixed $defaultValue): mixed;
+ /**
+ * Set the specified value at the specified key.
+ *
+ * This method returns the instance itself, so you can use it in fluent pattern.
+ *
+ * @param mixed $key The key
+ * @param mixed $value The value
+ *
+ * @return $this The map
+ */
public abstract function set (mixed $key, mixed $value) : static;
+ /**
+ * This method returns the instance itself, so you can use it in fluent pattern.
+ *
+ * @param mixed $key
+ *
+ * @return $this The map
+ */
public abstract function unset (mixed $key) : static;
+ /**
+ * Determine if the specified key exists.
+ *
+ * @param mixed $key The key to fetch
+ *
+ * @return bool true if the key exists; otherwise, false.
+ */
public abstract function has (mixed $key) : bool;
+ /**
+ * Determine if the specified value exists.
+ *
+ * @param mixed $value
+ *
+ * @return bool true if the value exists; otherwise, false
+ */
public abstract function contains (mixed $value) : bool;
///
@@ -29,18 +81,43 @@
/// Interface to provide accessing objects as arrays.
///
+ /**
+ * @link https://php.net/manual/en/arrayaccess.offsetexists.php
+ *
+ * @param mixed $offset The offset to assign the value to
+ * @return bool true if the offset exists; otherwise, false
+ */
public function offsetExists (mixed $offset) : bool {
return $this->has($offset);
}
+ /**
+ * @link https://php.net/manual/en/arrayaccess.offsetget.php
+ *
+ * @param mixed $offset The offset to assign the value to
+ * @return mixed The value at that offset
+ */
public function offsetGet (mixed $offset) : mixed {
return $this->get($offset);
}
+ /**
+ * Assign a value to the specified offset
+ *
+ * @link https://php.net/manual/en/arrayaccess.offsetset.php
+ *
+ * @param mixed $offset The offset to assign the value to
+ * @param mixed $value The value to set
+ */
public function offsetSet (mixed $offset, mixed $value) : void {
$this->set($offset, $value);
}
+ /**
+ * @link https://php.net/manual/en/arrayaccess.offsetunset.php
+ *
+ * @param mixed $offset The offset to assign the value to
+ */
public function offsetUnset (mixed $offset) : void {
$this->unset($offset);
}
diff --git a/omnitools/src/Collections/BaseVector.php b/omnitools/src/Collections/BaseVector.php
--- a/omnitools/src/Collections/BaseVector.php
+++ b/omnitools/src/Collections/BaseVector.php
@@ -7,11 +7,18 @@
use ArrayIterator;
use InvalidArgumentException;
use IteratorAggregate;
+use ReflectionException;
use Traversable;
use Keruald\OmniTools\Reflection\CallableElement;
use Keruald\OmniTools\Strings\Multibyte\OmniString;
+/**
+ * Abstract base class to represent arrays / lists / vectors.
+ *
+ * It also provides a concrete implementation for ArrayAccess interface.
+ *
+ */
abstract class BaseVector extends BaseCollection implements ArrayAccess, IteratorAggregate {
///
@@ -75,10 +82,16 @@
/// Interact with collection content at collection level
///
+ /**
+ * {@inheritDoc}
+ */
public function count () : int {
return count($this->items);
}
+ /**
+ * {@inheritDoc}
+ */
public function isEmpty () : bool {
return $this->count() === 0;
}
@@ -102,7 +115,9 @@
* If a value already exists, the value is still added
* as a duplicate.
*
- * @see update() when you need to only add unique values.
+ * This method returns the instance itself, so you can use it in fluent pattern.
+ *
+ * @see BaseVector::update() when you need to only add unique values
*/
public function append (iterable $iterable) : self {
foreach ($iterable as $value) {
@@ -113,12 +128,14 @@
}
/**
- * Append all elements of the specified iterable
- * to the current vector.
+ * Append all elements of the specified iterable to the current vector.
*
* If a value already exists, it is skipped.
*
- * @see append() when you need to always add everything.
+ * This method returns the instance itself, so you can use it in fluent pattern.
+ *
+ * @see BaseVector::append() when you need to always add everything
+ * @return $this
*/
public function update (iterable $iterable) : self {
foreach ($iterable as $value) {
@@ -131,10 +148,13 @@
}
/**
- * Replaces a part of the vector by the specified iterable.
+ * Replace a part of the vector by the specified iterable.
*
- * @param int $offset Allow to replace a part inside the vector by an iterable with keys starting at 0, by adding the specified offset.
- * @param int $len The maximum amount of elements to read. If 0, the read isn't bounded.
+ * This method returns the instance itself, so you can use it in fluent pattern.
+ *
+ * @param int $offset Allow to replace a part inside the vector by an iterable with keys starting at 0, by adding the specified offset
+ * @param int $len The maximum amount of elements to read. If 0, the read isn't bounded
+ * @return $this
*/
public function replace(iterable $iterable, int $offset = 0, int $len = 0) : self {
$itemsCount = 0;
@@ -152,7 +172,7 @@
}
/**
- * Gets a copy of the internal vector.
+ * Copy the vector into a PHP array.
*
* Scalar values (int, strings) are cloned.
* Objects are references to a specific objet, not a clone.
@@ -167,23 +187,58 @@
/// HOF :: generic
///
+ /**
+ * Create a new vector by applying a callback on each element of the vector.
+ *
+ *
+ *
+ * @param callable $callable The callback function to run for each element.
+ * @return self A new map with the mapped elements.
+ */
public function map (callable $callable) : self {
return new static(array_map($callable, $this->items));
}
+ /**
+ * Create a new vector by filtering each element of the vector
+ * according the return value of the specified callback function.
+ *
+ * Example:
+ *
+ * ```
+ * $words = new Vector(["foo", "bar", "quux", "xizzy"]);
+ *
+ * $threeLettersWords = $words->filter(
+ * fn(string $word) => strlen($word) === 3
+ * );
+ *
+ * // The new vector contains "foo" and "bar".
+ * ```
+ *
+ * @param callable $callable A callback function, which returns a boolean.
+ * When true, the element is kept.
+ * When false, the element is discarded.
+ * @return self A new map with filtered elements
+ *
+ * @throws ReflectionException when the callback isn't callable.
+ * @throws InvalidArgumentException when the callback doesn't have any argument.
+ */
public function filter (callable $callable) : self {
$argc = (new CallableElement($callable))->countArguments();
if ($argc === 0) {
- throw new InvalidArgumentException(
- "Callback should have at least one argument"
- );
+ throw new InvalidArgumentException(static::CB_ZERO_ARG);
}
$mode = (int)($argc > 1);
return new static(array_filter($this->items, $callable, $mode));
}
+ /**
+ * @param callable $callable
+ *
+ * @return $this
+ */
public function mapKeys (callable $callable) : self {
$mappedVector = [];
foreach ($this->items as $key => $value) {
@@ -336,7 +391,15 @@
/// IteratorAggregate
///
- public function getIterator () : Traversable {
+ /**
+ * Retrieve an iterator on the elements of the vector.
+ *
+ * This iterator also allows unsetting and modifying values and keys
+ * while iterating.
+ *
+ * @return ArrayIterator
+ */
+ public function getIterator () : ArrayIterator {
return new ArrayIterator($this->items);
}
diff --git a/omnitools/src/Collections/TraversableUtilities.php b/omnitools/src/Collections/TraversableUtilities.php
--- a/omnitools/src/Collections/TraversableUtilities.php
+++ b/omnitools/src/Collections/TraversableUtilities.php
@@ -9,9 +9,24 @@
use SimpleXMLElement;
use TypeError;
+/**
+ * Helper methods for iterables
+ */
class TraversableUtilities {
- public static function count ($countable) : int {
+ /**
+ * Count the number of elements of a countable value,
+ * or return 0 if the value is null or false.
+ *
+ * The count of 0 for a false or null value is offered
+ * as compatibility with legacy PHP behavior.
+ *
+ * @param mixed $countable
+ * @return int The count of elements in the collection
+ *
+ * @throws TypeError if $countable isn't countable, false or null.
+ */
+ public static function count (mixed $countable) : int {
if (is_countable($countable)) {
return count($countable);
}
@@ -23,6 +38,14 @@
throw new TypeError;
}
+ /**
+ * Iterate a collection and return the first element.
+ *
+ * @param iterable $iterable The collection to iterate
+ * @return mixed The first element of the collection
+ *
+ * @throws InvalidArgumentException if $iterable is empty
+ */
public static function first (iterable $iterable) : mixed {
foreach ($iterable as $value) {
return $value;
@@ -33,6 +56,15 @@
);
}
+ /**
+ * Iterate a collection and return the first element, if it exists.
+ * When the collection is empty, return a default value.
+ *
+ * @param iterable $iterable
+ * @param mixed|null $defaultValue
+ *
+ * @return mixed
+ */
public static function firstOr (
iterable $iterable, mixed $defaultValue = null
) : mixed {
diff --git a/omnitools/src/Collections/WeightedList.php b/omnitools/src/Collections/WeightedList.php
--- a/omnitools/src/Collections/WeightedList.php
+++ b/omnitools/src/Collections/WeightedList.php
@@ -7,6 +7,11 @@
use Iterator;
use IteratorAggregate;
+/**
+ * Represent a list of values associated to a weight.
+ *
+ * This class can represent the list in the HTTP_ACCEPT_LANGUAGE header.
+ */
class WeightedList implements IteratorAggregate, Countable {
/**
@@ -54,11 +59,19 @@
$this->addWeightedValue(WeightedValue::parse($expression));
}
+ /**
+ * Clear the list
+ */
public function clear () : void {
$this->list = [];
}
- public function getHeaviest () {
+ /**
+ * Get the value with the highest weight
+ *
+ * @return mixed The value with the higher weight associated
+ */
+ public function getHeaviest () : mixed {
$value = null;
foreach ($this->list as $candidate) {
@@ -70,6 +83,12 @@
return $value;
}
+ /**
+ * Sort the list according to the weights
+ *
+ * @return array An array of values, sorted from the highest weight
+ * to the lowest weight.
+ */
public function toSortedArray () : array {
$weights = [];
$values = [];
diff --git a/omnitools/src/Collections/WeightedValue.php b/omnitools/src/Collections/WeightedValue.php
--- a/omnitools/src/Collections/WeightedValue.php
+++ b/omnitools/src/Collections/WeightedValue.php
@@ -5,6 +5,14 @@
use TypeError;
+/**
+ * Represent a value associated to a weight.
+ *
+ * This class can represent a value from the HTTP_ACCEPT_LANGUAGE header.
+ *
+ * @property mixed $value The value
+ * @property float $weight The weight associated to this value
+ */
class WeightedValue implements Comparable {
///
@@ -74,6 +82,16 @@
/// Helper methods
///
+ /**
+ * Compare the weight of this value to the weight of another one.
+ *
+ * @param object $other The weighted value to compare to
+ * @return int 1 if this weight is greater than the other one
+ * -1 if this weight is lesser than the other one
+ * 0 if the two weights are equal
+ *
+ * @throws TypeError when the other object is not a WeightedValue instance.
+ */
public function compareTo (object $other) : int {
if (!$other instanceof WeightedValue) {
throw new TypeError;
diff --git a/omnitools/src/Culture/Rome/RomanNumerals.php b/omnitools/src/Culture/Rome/RomanNumerals.php
--- a/omnitools/src/Culture/Rome/RomanNumerals.php
+++ b/omnitools/src/Culture/Rome/RomanNumerals.php
@@ -5,8 +5,17 @@
use InvalidArgumentException;
+/**
+ * Convert between Hindu-Arabic and Roman numerals
+ */
final class RomanNumerals {
+ /**
+ * Convert a Hindu-Arabic number into a Roman numeral
+ * @param int $number The number to convert
+ *
+ * @return string The number expressed as a Roman numeral
+ */
public static function fromHinduArabic (int $number) : string {
self::assertStrictlyPositiveNumber($number);
@@ -20,7 +29,7 @@
}
/**
- * Provides a canonical table with hindu arabic numerals as keys,
+ * Provide a canonical table with hindu arabic numerals as keys,
* and Roman numerals as values.
*/
public static function getHinduArabicTable () : array {
diff --git a/omnitools/src/DateTime/DateStamp.php b/omnitools/src/DateTime/DateStamp.php
--- a/omnitools/src/DateTime/DateStamp.php
+++ b/omnitools/src/DateTime/DateStamp.php
@@ -8,6 +8,9 @@
use DateTime;
use InvalidArgumentException;
+/**
+ * Represent a YYYY-MM-DD date, without time information.
+ */
class DateStamp {
///
@@ -44,6 +47,12 @@
return self::parse($dateStamp);
}
+ /**
+ * Parse a string using the YYYYMMDD or YYYY-MMD-DD format
+ *
+ * @param string $date
+ * @return static
+ */
public static function parse (string $date) : self {
if (preg_match("/^[0-9]{4}\-[0-1][0-9]\-[0-3][0-9]$/", $date)) {
// YYYY-MM-DD
@@ -70,18 +79,30 @@
/// Convert methods
///
+ /**
+ * Get a UNIX time matching the date at 00:00:00 UTC
+ */
public function toUnixTime () : int {
return mktime(0, 0, 0, $this->month, $this->day, $this->year);
}
+ /**
+ * Convert into a PHP DateTime object
+ */
public function toDateTime () : DateTime {
return new DateTime($this->__toString());
}
+ /**
+ * Represent the date using YYYYMMDD format.
+ */
public function toShortString () : string {
return date('Ymd', $this->toUnixTime());
}
+ /**
+ * * Represent the date using YYYY-MM-DD format.
+ */
public function __toString () : string {
return date('Y-m-d', $this->toUnixTime());
}
diff --git a/omnitools/src/DateTime/UUIDv1TimeStamp.php b/omnitools/src/DateTime/UUIDv1TimeStamp.php
--- a/omnitools/src/DateTime/UUIDv1TimeStamp.php
+++ b/omnitools/src/DateTime/UUIDv1TimeStamp.php
@@ -7,6 +7,13 @@
use DateTimeInterface;
use InvalidArgumentException;
+/**
+ * Represent a timestamp as specified in RFC 4122 (UUID).
+ *
+ * This timestamp can be represented into a 60 bits vector as a count of
+ * 100-nanosecond intervals since 00:00:00.00, 15 October 1582 (the date of
+ * Gregorian reform to the Christian calendar).
+ */
class UUIDv1TimeStamp {
private BitsVector $bits;
diff --git a/omnitools/src/DateTime/UUIDv7TimeStamp.php b/omnitools/src/DateTime/UUIDv7TimeStamp.php
--- a/omnitools/src/DateTime/UUIDv7TimeStamp.php
+++ b/omnitools/src/DateTime/UUIDv7TimeStamp.php
@@ -7,6 +7,15 @@
use DateTimeInterface;
use InvalidArgumentException;
+/**
+ * Represent a timestamp as specified in draft-peabody-dispatch-new-uuid-format-03.
+ *
+ * This timestamp can be represented into a 48 bits vector from the current
+ * UNIX time, with a millisecond precision, ie the number of milliseconds
+ * since 1970-01-01 00:00:00.000.
+ *
+ * It ignores leap seconds.
+ */
class UUIDv7TimeStamp {
private BitsVector $bits;
diff --git a/omnitools/src/Debug/Debugger.php b/omnitools/src/Debug/Debugger.php
--- a/omnitools/src/Debug/Debugger.php
+++ b/omnitools/src/Debug/Debugger.php
@@ -3,20 +3,29 @@
namespace Keruald\OmniTools\Debug;
+/**
+ * Helper methods to debug PHP applications
+ */
class Debugger {
/**
- * Prints human-readable information about a variable, wrapped in a <pre> block
+ * Print human-readable information about a variable, wrapped in a `<pre>` block.
*
- * @param mixed $variable the variable to dump
+ * @param mixed $variable The variable to dump
*/
- public static function printVariable ($variable) : void {
+ public static function printVariable (mixed $variable) : void {
echo "<pre class='debug'>";
print_r($variable);
echo "</pre>";
}
- public static function printVariableAndDie ($variable) : void {
+ /**
+ * Print human-readable information about a variable, wrapped in a `<pre>`
+ * block, then halt execution.
+ *
+ * @param mixed $variable The variable to dump
+ */
+ public static function printVariableAndDie (mixed $variable) : never {
static::printVariable($variable);
die;
}
@@ -25,6 +34,11 @@
/// Comfort debug helper to register debug method in global space
///
+ /**
+ * Populate the global namespace with print_r() and dieprint_r() functions.
+ *
+ * They're convenient aliases for the static methods of this class.
+ */
public static function register () : void {
require_once '_register_to_global_space.php';
}
diff --git a/omnitools/src/Debug/_register_to_global_space.php b/omnitools/src/Debug/_register_to_global_space.php
--- a/omnitools/src/Debug/_register_to_global_space.php
+++ b/omnitools/src/Debug/_register_to_global_space.php
@@ -9,13 +9,34 @@
const GENERAL_ERROR = 117;
if (!function_exists("dprint_r")) {
- function dprint_r ($variable) {
+
+ /**
+ * Print human-readable information about a variable, wrapped in a `<pre>` block.
+ *
+ * To use this function in global namespace, you first need to register it
+ * by calling `Keruald\OmniTools\Debug\Debugger::register()`.
+ *
+ * @param mixed $variable The variable to dump
+ */
+ function dprint_r (mixed $variable) : void {
Debugger::printVariable($variable);
}
+
}
if (!function_exists("dieprint_r")) {
- function dieprint_r ($variable) {
+
+ /**
+ * Print human-readable information about a variable, wrapped in a `<pre>`
+ * block, then halt execution.
+ *
+ * To use this function in global namespace, you first need to register it
+ * by calling `Keruald\OmniTools\Debug\Debugger::register()`.
+ *
+ * @param mixed $variable The variable to dump
+ */
+ function dieprint_r (mixed $variable) : never {
Debugger::printVariableAndDie($variable);
}
+
}
diff --git a/omnitools/src/HTTP/Requests/AcceptedLanguages.php b/omnitools/src/HTTP/Requests/AcceptedLanguages.php
--- a/omnitools/src/HTTP/Requests/AcceptedLanguages.php
+++ b/omnitools/src/HTTP/Requests/AcceptedLanguages.php
@@ -5,12 +5,12 @@
use Keruald\OmniTools\Collections\WeightedList;
+/**
+ * Represent the accepted languages from an HTTP client request.
+ */
class AcceptedLanguages {
- /**
- * @var string
- */
- private $acceptedLanguages;
+ private string $acceptedLanguages;
///
/// Constructor
@@ -20,6 +20,9 @@
$this->acceptedLanguages = $acceptedLanguages;
}
+ /**
+ * Build a new instance by extracting from server headers
+ */
public static function fromServer () : self {
return new self(self::extractFromHeaders());
}
@@ -28,10 +31,19 @@
/// Helper methods to determine the languages
///
+ /**
+ * @return string The content of HTTP_ACCEPT_LANGUAGE header
+ */
public static function extractFromHeaders () : string {
return $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? "";
}
+ /**
+ * Get language codes, sorted by preference.
+ *
+ * @return array A sorted array of the accepted langages by order
+ * from the most preferred to the least preferred
+ */
public function getLanguageCodes () : array {
return WeightedList::parse($this->acceptedLanguages)
->toSortedArray();
diff --git a/omnitools/src/HTTP/Requests/RemoteAddress.php b/omnitools/src/HTTP/Requests/RemoteAddress.php
--- a/omnitools/src/HTTP/Requests/RemoteAddress.php
+++ b/omnitools/src/HTTP/Requests/RemoteAddress.php
@@ -5,12 +5,14 @@
use Keruald\OmniTools\Network\IP;
+/**
+ * Represent the client remote address and extract that information from
+ * relevant headers, with support for HTTP_X_FORWARDED_FOR, legacy proxies
+ * headers and REMOTE_ADDR.
+ */
class RemoteAddress {
- /**
- * @var string
- */
- private $remoteAddress;
+ private string $remoteAddress;
///
/// Constructor
@@ -75,6 +77,11 @@
/// Data sources
///
+ /**
+ * Gets the list of headers to look for a remote address value.
+ *
+ * @return string[] A list of headers to check for a relevant value.
+ */
public static function listRemoteAddressHeaders () : array {
return [
// Standard header provided by draft-ietf-appsawg-http-forwarded-10
diff --git a/omnitools/src/HTTP/Requests/Request.php b/omnitools/src/HTTP/Requests/Request.php
--- a/omnitools/src/HTTP/Requests/Request.php
+++ b/omnitools/src/HTTP/Requests/Request.php
@@ -3,6 +3,9 @@
namespace Keruald\OmniTools\HTTP\Requests;
+/**
+ * Helpers method to parse an HTTP request
+ */
class Request {
use WithAcceptedLanguages;
diff --git a/omnitools/src/HTTP/Requests/WithAcceptedLanguages.php b/omnitools/src/HTTP/Requests/WithAcceptedLanguages.php
--- a/omnitools/src/HTTP/Requests/WithAcceptedLanguages.php
+++ b/omnitools/src/HTTP/Requests/WithAcceptedLanguages.php
@@ -8,7 +8,7 @@
trait WithAcceptedLanguages {
/**
- * Gets the languages accepted by the browser, by order of priority.
+ * Get the languages accepted by the browser, by order of priority.
*
* This will read the HTTP_ACCEPT_LANGUAGE variable sent by the browser in the
* HTTP request.
diff --git a/omnitools/src/HTTP/Requests/WithRemoteAddress.php b/omnitools/src/HTTP/Requests/WithRemoteAddress.php
--- a/omnitools/src/HTTP/Requests/WithRemoteAddress.php
+++ b/omnitools/src/HTTP/Requests/WithRemoteAddress.php
@@ -6,7 +6,7 @@
trait WithRemoteAddress {
/**
- * Gets remote IP address.
+ * Get remote IP address.
*
* This is intended as a drop-in replacement for $_SERVER['REMOTE_ADDR'],
* which takes in consideration proxy values, blindly trusted.
@@ -22,6 +22,11 @@
return RemoteAddress::fromServer()->getClientAddress();
}
+ /**
+ * Determine if the specified remote address is the local machine.
+ *
+ * @return bool
+ */
public static function isFromLocalHost () : bool {
return RemoteAddress::fromServer()->isFromLocalHost();
}
diff --git a/omnitools/src/HTTP/URL.php b/omnitools/src/HTTP/URL.php
--- a/omnitools/src/HTTP/URL.php
+++ b/omnitools/src/HTTP/URL.php
@@ -5,6 +5,9 @@
use Keruald\OmniTools\Strings\Multibyte\OmniString;
+/**
+ * Represent a URL
+ */
class URL {
///
@@ -32,15 +35,9 @@
/// Private members
///
- /**
- * @var string
- */
- private $url;
+ private string $url;
- /**
- * @var int
- */
- private $queryEncoding;
+ private int $queryEncoding;
///
/// Constructors
@@ -52,6 +49,16 @@
$this->queryEncoding = $queryEncoding;
}
+ /**
+ * Build a URL from specified protocol, domain and query.
+ *
+ * @param string $protocol The protocol, e.g. "http", "https" or "wss"
+ * @param string $domain The fully qualified domain name, e.g. "www.acme.tld"
+ * @param string $query The query part of the URL, including the initial /, e.g. "/foo"
+ * @param int $queryEncoding The format to use to encode the query
+ *
+ * @return static
+ */
public static function compose (string $protocol, string $domain,
string $query,
$queryEncoding = self::ENCODE_RFC3986_SLASH_EXCEPTED
@@ -60,7 +67,6 @@
->update($protocol, $domain, $query);
}
-
///
/// Getters and setters
///
@@ -78,6 +84,9 @@
return explode("/", $matches[1], 2);
}
+ /**
+ * Get the fully qualified domain name, without protocol information
+ */
public function getDomain () : string {
if (strpos($this->url, "://") === false) {
return "";
@@ -155,6 +164,14 @@
return $this;
}
+ /**
+ * Normalize the query according the specified encoding for this URL.
+ *
+ * @param string $query
+ * @return string
+ *
+ * @see URL::beautifyQuery() for the inverse operation (decode)
+ */
public function normalizeQuery (string $query) : string {
switch ($this->queryEncoding) {
case self::ENCODE_RFC3986_SLASH_EXCEPTED:
@@ -174,6 +191,13 @@
throw new \Exception('Unexpected encoding value');
}
+ /**
+ * @param string $query
+ *
+ * @return string
+ *
+ * @see URL::normalizeQuery() for the inverse operation (encode)
+ */
public function beautifyQuery (string $query) : string {
switch ($this->queryEncoding) {
case self::ENCODE_RFC3986_SLASH_EXCEPTED:
@@ -193,10 +217,22 @@
throw new \Exception('Unexpected encoding value');
}
+ /**
+ * Normalize a domain name, converting IDN to ASCII representation.
+ *
+ * @param string The UTF-8 domain string, e.g. dæghrefn.nasqueron.org
+ * @return string The IDN ACE form representation for the domain, e.g. xn--dghrefn-mxa.nasqueron.org
+ */
public static function normalizeDomain (string $domain) : string {
return \idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46);
}
+ /**
+ * Beautify a domain name, converting IDN to UTF-8 representation.
+ *
+ * @param string The IDN ACE form representation for the domain, e.g. xn--dghrefn-mxa.nasqueron.org
+ * @return string The UTF-8 domain string, e.g. dæghrefn.nasqueron.org
+ */
public static function beautifyDomain (string $domain) : string {
return \idn_to_utf8($domain, 0, INTL_IDNA_VARIANT_UTS46);
}
diff --git a/omnitools/src/IO/Directory.php b/omnitools/src/IO/Directory.php
--- a/omnitools/src/IO/Directory.php
+++ b/omnitools/src/IO/Directory.php
@@ -2,6 +2,9 @@
namespace Keruald\OmniTools\IO;
+/**
+ * Represent a directory or folder in a filesystem
+ */
class Directory {
///
diff --git a/omnitools/src/IO/File.php b/omnitools/src/IO/File.php
--- a/omnitools/src/IO/File.php
+++ b/omnitools/src/IO/File.php
@@ -3,6 +3,9 @@
namespace Keruald\OmniTools\IO;
+/**
+ * Represent a file in a filesystem
+ */
class File {
/**
diff --git a/omnitools/src/IO/FileUtilities.php b/omnitools/src/IO/FileUtilities.php
--- a/omnitools/src/IO/FileUtilities.php
+++ b/omnitools/src/IO/FileUtilities.php
@@ -3,6 +3,9 @@
namespace Keruald\OmniTools\IO;
+/**
+ * Static helper methods to manipulate files
+ */
class FileUtilities {
public static function getExtension (string $filename) : string {
diff --git a/omnitools/src/Identifiers/Random.php b/omnitools/src/Identifiers/Random.php
--- a/omnitools/src/Identifiers/Random.php
+++ b/omnitools/src/Identifiers/Random.php
@@ -9,19 +9,25 @@
use Keruald\OmniTools\Strings\Multibyte\StringUtilities;
+/**
+ * Random number generators and random pickers using cryptographically-secure
+ * pseudorandom number generator (CPRNG)
+ */
class Random {
/**
- * @return string 32 random hexadecimal characters
+ * Generate a 32 random hexadecimal characters string
*/
public static function generateHexHash () : string {
return UUID::UUIDv4WithoutHyphens();
}
/**
- * @param string $format A for letters, 1 for digits, e.g. AAA111
+ * Generate a random string according the specified format.
*
- * @return string a random string based on the format e.g. ZCK530
+ * @param string $format A for uppercase letter, a for lowercase letter,
+ * 1 for digit, e.g. "AAA111"
+ * @return string a random string based on the format, e.g. "ZCK530"
*/
public static function generateString (string $format) : string {
$randomString = "";
@@ -35,9 +41,14 @@
}
/**
- * @param string $format A for letters, 1 for digits, e.g. A
+ * Generate a random character according the specified format.
+ *
+ * @param string $format A for uppercase letter, a for lowercase letter,
+ * 1 for digit, e.g. "A"
*
* @return string a random string based on the format e.g. Z
+ *
+ * @see Random::generateString() for a full string of several characters
*/
public static function generateCharacter (string $format) : string {
return self::getPicker(self::normalizeFormat($format))();
@@ -45,6 +56,8 @@
/**
+ * Generate the specified count of random bytes and represent them in base64.
+ *
* @throws Exception if an appropriate source of randomness cannot be found.
*/
public static function generateIdentifier (int $bytes_count) : string {
@@ -136,6 +149,15 @@
}
/**
+ * Generate a monotonically increasing series of integers.
+ *
+ * Random numbers will be picked in the random number[$min, $max]
+ *
+ * @param int $min The lower bound | ∀x ∈ S, x >= $min
+ * @param int $max The upper bound | ∀x ∈ S, x <= $max
+ * @param int $count The number of elements in the series S
+ * @return int[] An array of $count integers, each between $min and $max
+ *
* @throws InvalidArgumentException if [$min, $max] doesn't have at least $count elements.
* @throws Exception if an appropriate source of randomness cannot be found.
*/
diff --git a/omnitools/src/Identifiers/UUID.php b/omnitools/src/Identifiers/UUID.php
--- a/omnitools/src/Identifiers/UUID.php
+++ b/omnitools/src/Identifiers/UUID.php
@@ -12,8 +12,11 @@
use Keruald\OmniTools\DateTime\UUIDv7TimeStamp;
/**
- * Allow generating and representing UUID by implementing both RFC 4122
- * and proposed extension to UUIDv6, UUIDv7 and UUIDv8.
+ * Allow generating and representing UUID. This static class contains helper
+ * methods to generate, validate, format and convert UUID.
+ *
+ * The UUID class implements both RFC 4122 and proposed extension to UUIDv6,
+ * UUIDv7 and UUIDv8.
*
* A UUID is a universal identified with good local and global uniqueness
* on the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx where x is hexadecimal.
@@ -405,8 +408,8 @@
}
/**
- * Allow to generate a UUIDv7 for known timestamp and known random values,
- * when the timestamp is available as a signed 48-bits integer.
+ * Generate a UUIDv7 for known timestamp and known random values,
+ * with the timestamp expressed as a 48-bits signed integer.
*
* @param int $unixTimestampMs A 48 bits signed integer for timestamp
* @param int $randA A 12 bits value for random A number
@@ -429,7 +432,7 @@
///
/**
- * Generate a UUIDv8 with three custom values.
+ * Generate a UUIDv8 for specified custom values.
*
* According to proposed draft, the UUIDv8 lets the implementation decides
* of the bits' layout. Accordingly, this method give you the control
diff --git a/omnitools/src/OS/CurrentOS.php b/omnitools/src/OS/CurrentOS.php
--- a/omnitools/src/OS/CurrentOS.php
+++ b/omnitools/src/OS/CurrentOS.php
@@ -3,12 +3,23 @@
namespace Keruald\OmniTools\OS;
+/**
+ * Get information about the current operating system
+ */
class CurrentOS {
+ /**
+ * Determine if the system runs Windows, including if PHP is built
+ * for Cygwin (but not WSL)
+ */
public static function isWindows () : bool {
return PHP_OS === 'CYGWIN' || self::isPureWindows();
}
+ /**
+ * Determine if the system runs Windows, with PHP built natively
+ * (ie not for Cygwin).
+ */
public static function isPureWindows () : bool {
return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
}
diff --git a/omnitools/src/OS/CurrentProcess.php b/omnitools/src/OS/CurrentProcess.php
--- a/omnitools/src/OS/CurrentProcess.php
+++ b/omnitools/src/OS/CurrentProcess.php
@@ -3,10 +3,13 @@
namespace Keruald\OmniTools\OS;
+/**
+ * Get information about the current process, ie the PHP interpreter.
+ */
class CurrentProcess {
/**
- * Determines if the current process, ie the PHP interpreter,
+ * Determine if the current process, ie the PHP interpreter,
* runs as root on UNIX systems or in elevated mode on Windows.
*
* Cygwin processes are considered as Windows processes.
@@ -31,7 +34,7 @@
}
/**
- * Determines the username of the current process, ie the PHP interpreter.
+ * Determine the username of the current process, ie the PHP interpreter.
*/
public static function getUsername () : string {
if (!extension_loaded("posix")) {
diff --git a/omnitools/src/OS/Environment.php b/omnitools/src/OS/Environment.php
--- a/omnitools/src/OS/Environment.php
+++ b/omnitools/src/OS/Environment.php
@@ -6,15 +6,27 @@
use Keruald\OmniTools\DataTypes\Option\Option;
+/**
+ * Allow accessing environment variables
+ */
class Environment {
+ /**
+ * Determine if an environment variable exists.
+ *
+ * @param string $key The environment variable name
+ * @return bool
+ */
public static function has (string $key) : bool {
return array_key_exists($key, $_ENV)
|| array_key_exists($key, $_SERVER);
}
/**
- * @throws InvalidArgumentException
+ * Get a specific environment variable.
+ *
+ * @param string $key The environment variable name
+ * @throws InvalidArgumentException if the variable doesn't exist
*/
public static function get (string $key) : string {
if (!self::has($key)) {
@@ -37,6 +49,18 @@
return Option::from($value);
}
+ /**
+ * Get a specific environment variable, or a default value if it doesn't
+ * exist.
+ *
+ * If the variable is set with an empty string value, this method will
+ * consider it as a legitimate value and so return an empty string.
+ *
+ * @param string $key The environment variable name
+ * @param string $default The default value to use when not existing
+ *
+ * @return string The environment variable, or the default value.
+ */
public static function getOr (string $key, string $default) : string {
return $_ENV[$key] ?? $_SERVER[$key] ?? $default;
}
diff --git a/omnitools/src/Reflection/CallableElement.php b/omnitools/src/Reflection/CallableElement.php
--- a/omnitools/src/Reflection/CallableElement.php
+++ b/omnitools/src/Reflection/CallableElement.php
@@ -10,6 +10,10 @@
use ReflectionFunctionAbstract;
use ReflectionMethod;
+/**
+ * Represent a callable element, ie a reference to a closure, method, function
+ * PHP is able to use as a callback.
+ */
class CallableElement {
private ReflectionFunctionAbstract $callable;
@@ -68,6 +72,25 @@
);
}
+ /**
+ * Count the number of arguments the callable expects.
+ *
+ * This method can be used to validate callback passed by users
+ * to a function you design to accept callables.
+ *
+ * Example from this library:
+ *
+ * ```
+ * public function filter (callable $callable) : self {
+ * $argc = (new CallableElement($callable))->countArguments();
+ *
+ * if ($argc === 0) {
+ * throw new InvalidArgumentException(static::CB_ZERO_ARG);
+ * }
+ *
+ * […]
+ * ```
+ */
public function countArguments () : int {
return $this->callable->getNumberOfParameters();
}
diff --git a/omnitools/src/Reflection/CodeFile.php b/omnitools/src/Reflection/CodeFile.php
--- a/omnitools/src/Reflection/CodeFile.php
+++ b/omnitools/src/Reflection/CodeFile.php
@@ -4,12 +4,23 @@
use Keruald\OmniTools\IO\File;
+/**
+ * Represent a PHP code file.
+ *
+ * This class has been designed to be used in a class autoloader,
+ * but can be used independently.
+ */
class CodeFile extends File {
///
/// Include methods
///
+ /**
+ * Try to include the code file in the current application.
+ *
+ * @return bool false if it can't be included; otherwise, true
+ */
public function tryInclude () : bool {
if (!$this->canBeIncluded()) {
return false;
@@ -20,6 +31,11 @@
return true;
}
+ /**
+ * Determine if the code file can be included in the current application.
+ *
+ * @return bool if the file can be included; otherwise, false
+ */
public function canBeIncluded () : bool {
return $this->exists() && $this->isReadable();
}
diff --git a/omnitools/src/Registration/Autoloader.php b/omnitools/src/Registration/Autoloader.php
--- a/omnitools/src/Registration/Autoloader.php
+++ b/omnitools/src/Registration/Autoloader.php
@@ -3,12 +3,24 @@
namespace Keruald\OmniTools\Registration;
+/**
+ * This class offer SPL Autoloader for any PSR-4 namespace or for this library
+ * itself.
+ */
class Autoloader {
///
/// PSR-4
///
+ /**
+ * Register an autoloader for a PSR-4 namespace,
+ * enabling fosr classes traits and interfaces in that namespace to be
+ * automatically loaded if they are not yet defined.
+ *
+ * @param string $namespace
+ * @param string $path
+ */
public static function registerPSR4 (string $namespace, string $path) : void {
$loader = new PSR4\Autoloader($namespace, $path);
$loader->register();
@@ -18,6 +30,23 @@
/// Methods to register OmniTools library
///
+ /**
+ * Register the Keruald OmniTools PSR-4 classes.
+ *
+ * This method is convenient when you don't use Composer or any other
+ * mechanism.
+ *
+ * For example if you've put the library in your includes/ directory:
+ *
+ * ```
+ * use Keruald\OmniTools\Registration\Autoloader as KerualdLoader;
+ *
+ * require_once "includes/omnitools/Registration/Autoloader.php";
+ * KerualdLoader::selfRegister();
+ * ```
+ * You don't need to use this method if you already use a PSR-4 compatible
+ * autoloader like Composer + require vendor/autoload.php.
+ */
public static function selfRegister () : void {
// The PSR-4 autoloader needs those classes as dependencies:
require_once __DIR__ . "/PSR4/Autoloader.php";
@@ -28,6 +57,13 @@
self::registerPSR4("Keruald\\OmniTools\\", self::getLibraryPath());
}
+ /**
+ * Gets the Keruald OmniTools library path.
+ *
+ * The path matches a PSR-4 namespace for Keruald\OmniTools.
+ *
+ * @return string The library path.
+ */
public static function getLibraryPath () : string {
return dirname(__DIR__);
}
diff --git a/omnitools/src/Registration/PSR4/PSR4Namespace.php b/omnitools/src/Registration/PSR4/PSR4Namespace.php
--- a/omnitools/src/Registration/PSR4/PSR4Namespace.php
+++ b/omnitools/src/Registration/PSR4/PSR4Namespace.php
@@ -6,6 +6,9 @@
use Keruald\OmniTools\IO\Directory;
use Keruald\OmniTools\IO\File;
+/**
+ * Represent a PSR-4 namespace. Allow discovering classes.
+ */
class PSR4Namespace {
public function __construct (
@@ -22,7 +25,7 @@
* Discover classes in the namespace folder following PSR-4 convention,
* directly at top-level, ignoring subdirectories.
*
- * @see discoverRecursive
+ * @see PSR4Namespace::discoverRecursive
* @return string[]
*/
public function discover () : array {

File Metadata

Mime Type
text/plain
Expires
Wed, Apr 22, 10:37 (17 h, 33 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3648049
Default Alt Text
D2810.id10636.diff (48 KB)

Event Timeline