Page Menu
Home
DevCentral
Search
Configure Global Search
Log In
Files
F26407789
D2810.id10636.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
48 KB
Referenced Files
None
Subscribers
None
D2810.id10636.diff
View Options
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
Details
Attached
Mime Type
text/plain
Expires
Thu, Apr 23, 16:07 (17 h, 6 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3648049
Default Alt Text
D2810.id10636.diff (48 KB)
Attached To
Mode
D2810: Generate and enrich documentation
Attached
Detach File
Event Timeline
Log In to Comment