Update website

This commit is contained in:
Guilhem Lavaux 2024-11-19 09:35:33 +01:00
parent bb4b0f9be8
commit 011b183e28
4263 changed files with 3014 additions and 720369 deletions

View file

@ -1,22 +0,0 @@
Copyright (c) 2017, Ben Scholzen 'DASPRiD'
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,164 +0,0 @@
# PHP 7.1 enums
[![Build Status](https://travis-ci.org/DASPRiD/Enum.svg?branch=master)](https://travis-ci.org/DASPRiD/Enum)
[![Coverage Status](https://coveralls.io/repos/github/DASPRiD/Enum/badge.svg?branch=master)](https://coveralls.io/github/DASPRiD/Enum?branch=master)
[![Latest Stable Version](https://poser.pugx.org/dasprid/enum/v/stable)](https://packagist.org/packages/dasprid/enum)
[![Total Downloads](https://poser.pugx.org/dasprid/enum/downloads)](https://packagist.org/packages/dasprid/enum)
[![License](https://poser.pugx.org/dasprid/enum/license)](https://packagist.org/packages/dasprid/enum)
It is a well known fact that PHP is missing a basic enum type, ignoring the rather incomplete `SplEnum` implementation
which is only available as a PECL extension. There are also quite a few other userland enum implementations around,
but all of them have one or another compromise. This library tries to close that gap as far as PHP allows it to.
## Usage
### Basics
At its core, there is the `DASPRiD\Enum\AbstractEnum` class, which by default will work with constants like any other
enum implementation you might know. The first clear difference is that you should define all the constants as protected
(so nobody outside your class can read them but the `AbstractEnum` can still do so). The other even mightier difference
is that, for simple enums, the value of the constant doesn't matter at all. Let's have a look at a simple example:
```php
use DASPRiD\Enum\AbstractEnum;
/**
* @method static self MONDAY()
* @method static self TUESDAY()
* @method static self WEDNESDAY()
* @method static self THURSDAY()
* @method static self FRIDAY()
* @method static self SATURDAY()
* @method static self SUNDAY()
*/
final class WeekDay extends AbstractEnum
{
protected const MONDAY = null;
protected const TUESDAY = null;
protected const WEDNESDAY = null;
protected const THURSDAY = null;
protected const FRIDAY = null;
protected const SATURDAY = null;
protected const SUNDAY = null;
}
```
If you need to provide constants for either internal use or public use, you can mark them as either private or public,
in which case they will be ignored by the enum, which only considers protected constants as valid values. As you can
see, we specifically defined the generated magic methods in a class level doc block, so anyone using this class will
automatically have proper auto-completion in their IDE. Now since you have defined the enum, you can simply use it like
that:
```php
function tellItLikeItIs(WeekDay $weekDay)
{
switch ($weekDay) {
case WeekDay::MONDAY():
echo 'Mondays are bad.';
break;
case WeekDay::FRIDAY():
echo 'Fridays are better.';
break;
case WeekDay::SATURDAY():
case WeekDay::SUNDAY():
echo 'Weekends are best.';
break;
default:
echo 'Midweek days are so-so.';
}
}
tellItLikeItIs(WeekDay::MONDAY());
tellItLikeItIs(WeekDay::WEDNESDAY());
tellItLikeItIs(WeekDay::FRIDAY());
tellItLikeItIs(WeekDay::SATURDAY());
tellItLikeItIs(WeekDay::SUNDAY());
```
### More complex example
Of course, all enums are singletons, which are not cloneable or serializable. Thus you can be sure that there is always
just one instance of the same type. Of course, the values of constants are not completely useless, let's have a look at
a more complex example:
```php
use DASPRiD\Enum\AbstractEnum;
/**
* @method static self MERCURY()
* @method static self VENUS()
* @method static self EARTH()
* @method static self MARS()
* @method static self JUPITER()
* @method static self SATURN()
* @method static self URANUS()
* @method static self NEPTUNE()
*/
final class Planet extends AbstractEnum
{
protected const MERCURY = [3.303e+23, 2.4397e6];
protected const VENUS = [4.869e+24, 6.0518e6];
protected const EARTH = [5.976e+24, 6.37814e6];
protected const MARS = [6.421e+23, 3.3972e6];
protected const JUPITER = [1.9e+27, 7.1492e7];
protected const SATURN = [5.688e+26, 6.0268e7];
protected const URANUS = [8.686e+25, 2.5559e7];
protected const NEPTUNE = [1.024e+26, 2.4746e7];
/**
* Universal gravitational constant.
*
* @var float
*/
private const G = 6.67300E-11;
/**
* Mass in kilograms.
*
* @var float
*/
private $mass;
/**
* Radius in meters.
*
* @var float
*/
private $radius;
protected function __construct(float $mass, float $radius)
{
$this->mass = $mass;
$this->radius = $radius;
}
public function mass() : float
{
return $this->mass;
}
public function radius() : float
{
return $this->radius;
}
public function surfaceGravity() : float
{
return self::G * $this->mass / ($this->radius * $this->radius);
}
public function surfaceWeight(float $otherMass) : float
{
return $otherMass * $this->surfaceGravity();
}
}
$myMass = 80;
foreach (Planet::values() as $planet) {
printf("Your weight on %s is %f\n", $planet, $planet->surfaceWeight($myMass));
}
```

View file

@ -1,31 +0,0 @@
{
"name": "dasprid/enum",
"description": "PHP 7.1 enum implementation",
"license": "BSD-2-Clause",
"authors": [
{
"name": "Ben Scholzen 'DASPRiD'",
"email": "mail@dasprids.de",
"homepage": "https://dasprids.de/",
"role": "Developer"
}
],
"keywords": [
"enum",
"map"
],
"require-dev": {
"phpunit/phpunit": "^7 | ^8 | ^9",
"squizlabs/php_codesniffer": "^3.4"
},
"autoload": {
"psr-4": {
"DASPRiD\\Enum\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"DASPRiD\\EnumTest\\": "test/"
}
}
}

View file

@ -1,241 +0,0 @@
<?php
declare(strict_types = 1);
namespace DASPRiD\Enum;
use DASPRiD\Enum\Exception\CloneNotSupportedException;
use DASPRiD\Enum\Exception\IllegalArgumentException;
use DASPRiD\Enum\Exception\MismatchException;
use DASPRiD\Enum\Exception\SerializeNotSupportedException;
use DASPRiD\Enum\Exception\UnserializeNotSupportedException;
use ReflectionClass;
abstract class AbstractEnum
{
/**
* @var string
*/
private $name;
/**
* @var int
*/
private $ordinal;
/**
* @var array<string, array<string, static>>
*/
private static $values = [];
/**
* @var array<string, bool>
*/
private static $allValuesLoaded = [];
/**
* @var array<string, array>
*/
private static $constants = [];
/**
* The constructor is private by default to avoid arbitrary enum creation.
*
* When creating your own constructor for a parameterized enum, make sure to declare it as protected, so that
* the static methods are able to construct it. Avoid making it public, as that would allow creation of
* non-singleton enum instances.
*/
private function __construct()
{
}
/**
* Magic getter which forwards all calls to {@see self::valueOf()}.
*
* @return static
*/
final public static function __callStatic(string $name, array $arguments) : self
{
return static::valueOf($name);
}
/**
* Returns an enum with the specified name.
*
* The name must match exactly an identifier used to declare an enum in this type (extraneous whitespace characters
* are not permitted).
*
* @return static
* @throws IllegalArgumentException if the enum has no constant with the specified name
*/
final public static function valueOf(string $name) : self
{
if (isset(self::$values[static::class][$name])) {
return self::$values[static::class][$name];
}
$constants = self::constants();
if (array_key_exists($name, $constants)) {
return self::createValue($name, $constants[$name][0], $constants[$name][1]);
}
throw new IllegalArgumentException(sprintf('No enum constant %s::%s', static::class, $name));
}
/**
* @return static
*/
private static function createValue(string $name, int $ordinal, array $arguments) : self
{
$instance = new static(...$arguments);
$instance->name = $name;
$instance->ordinal = $ordinal;
self::$values[static::class][$name] = $instance;
return $instance;
}
/**
* Obtains all possible types defined by this enum.
*
* @return static[]
*/
final public static function values() : array
{
if (isset(self::$allValuesLoaded[static::class])) {
return self::$values[static::class];
}
if (! isset(self::$values[static::class])) {
self::$values[static::class] = [];
}
foreach (self::constants() as $name => $constant) {
if (array_key_exists($name, self::$values[static::class])) {
continue;
}
static::createValue($name, $constant[0], $constant[1]);
}
uasort(self::$values[static::class], function (self $a, self $b) {
return $a->ordinal() <=> $b->ordinal();
});
self::$allValuesLoaded[static::class] = true;
return self::$values[static::class];
}
private static function constants() : array
{
if (isset(self::$constants[static::class])) {
return self::$constants[static::class];
}
self::$constants[static::class] = [];
$reflectionClass = new ReflectionClass(static::class);
$ordinal = -1;
foreach ($reflectionClass->getReflectionConstants() as $reflectionConstant) {
if (! $reflectionConstant->isProtected()) {
continue;
}
$value = $reflectionConstant->getValue();
self::$constants[static::class][$reflectionConstant->name] = [
++$ordinal,
is_array($value) ? $value : []
];
}
return self::$constants[static::class];
}
/**
* Returns the name of this enum constant, exactly as declared in its enum declaration.
*
* Most programmers should use the {@see self::__toString()} method in preference to this one, as the toString
* method may return a more user-friendly name. This method is designed primarily for use in specialized situations
* where correctness depends on getting the exact name, which will not vary from release to release.
*/
final public function name() : string
{
return $this->name;
}
/**
* Returns the ordinal of this enumeration constant (its position in its enum declaration, where the initial
* constant is assigned an ordinal of zero).
*
* Most programmers will have no use for this method. It is designed for use by sophisticated enum-based data
* structures.
*/
final public function ordinal() : int
{
return $this->ordinal;
}
/**
* Compares this enum with the specified object for order.
*
* Returns negative integer, zero or positive integer as this object is less than, equal to or greater than the
* specified object.
*
* Enums are only comparable to other enums of the same type. The natural order implemented by this method is the
* order in which the constants are declared.
*
* @throws MismatchException if the passed enum is not of the same type
*/
final public function compareTo(self $other) : int
{
if (! $other instanceof static) {
throw new MismatchException(sprintf(
'The passed enum %s is not of the same type as %s',
get_class($other),
static::class
));
}
return $this->ordinal - $other->ordinal;
}
/**
* Forbid cloning enums.
*
* @throws CloneNotSupportedException
*/
final public function __clone()
{
throw new CloneNotSupportedException();
}
/**
* Forbid serializing enums.
*
* @throws SerializeNotSupportedException
*/
final public function __sleep() : array
{
throw new SerializeNotSupportedException();
}
/**
* Forbid unserializing enums.
*
* @throws UnserializeNotSupportedException
*/
final public function __wakeup() : void
{
throw new UnserializeNotSupportedException();
}
/**
* Turns the enum into a string representation.
*
* You may override this method to give a more user-friendly version.
*/
public function __toString() : string
{
return $this->name;
}
}

View file

@ -1,375 +0,0 @@
<?php
declare(strict_types = 1);
namespace DASPRiD\Enum;
use DASPRiD\Enum\Exception\ExpectationException;
use DASPRiD\Enum\Exception\IllegalArgumentException;
use IteratorAggregate;
use Serializable;
use Traversable;
/**
* A specialized map implementation for use with enum type keys.
*
* All of the keys in an enum map must come from a single enum type that is specified, when the map is created. Enum
* maps are represented internally as arrays. This representation is extremely compact and efficient.
*
* Enum maps are maintained in the natural order of their keys (the order in which the enum constants are declared).
* This is reflected in the iterators returned by the collection views {@see self::getIterator()} and
* {@see self::values()}.
*
* Iterators returned by the collection views are not consistent: They may or may not show the effects of modifications
* to the map that occur while the iteration is in progress.
*/
final class EnumMap implements Serializable, IteratorAggregate
{
/**
* The class name of the key.
*
* @var string
*/
private $keyType;
/**
* The type of the value.
*
* @var string
*/
private $valueType;
/**
* @var bool
*/
private $allowNullValues;
/**
* All of the constants comprising the enum, cached for performance.
*
* @var array<int, AbstractEnum>
*/
private $keyUniverse;
/**
* Array representation of this map. The ith element is the value to which universe[i] is currently mapped, or null
* if it isn't mapped to anything, or NullValue if it's mapped to null.
*
* @var array<int, mixed>
*/
private $values;
/**
* @var int
*/
private $size = 0;
/**
* Creates a new enum map.
*
* @param string $keyType the type of the keys, must extend AbstractEnum
* @param string $valueType the type of the values
* @param bool $allowNullValues whether to allow null values
* @throws IllegalArgumentException when key type does not extend AbstractEnum
*/
public function __construct(string $keyType, string $valueType, bool $allowNullValues)
{
if (! is_subclass_of($keyType, AbstractEnum::class)) {
throw new IllegalArgumentException(sprintf(
'Class %s does not extend %s',
$keyType,
AbstractEnum::class
));
}
$this->keyType = $keyType;
$this->valueType = $valueType;
$this->allowNullValues = $allowNullValues;
$this->keyUniverse = $keyType::values();
$this->values = array_fill(0, count($this->keyUniverse), null);
}
/**
* Checks whether the map types match the supplied ones.
*
* You should call this method when an EnumMap is passed to you and you want to ensure that it's made up of the
* correct types.
*
* @throws ExpectationException when supplied key type mismatches local key type
* @throws ExpectationException when supplied value type mismatches local value type
* @throws ExpectationException when the supplied map allows null values, abut should not
*/
public function expect(string $keyType, string $valueType, bool $allowNullValues) : void
{
if ($keyType !== $this->keyType) {
throw new ExpectationException(sprintf(
'Callee expected an EnumMap with key type %s, but got %s',
$keyType,
$this->keyType
));
}
if ($valueType !== $this->valueType) {
throw new ExpectationException(sprintf(
'Callee expected an EnumMap with value type %s, but got %s',
$keyType,
$this->keyType
));
}
if ($allowNullValues !== $this->allowNullValues) {
throw new ExpectationException(sprintf(
'Callee expected an EnumMap with nullable flag %s, but got %s',
($allowNullValues ? 'true' : 'false'),
($this->allowNullValues ? 'true' : 'false')
));
}
}
/**
* Returns the number of key-value mappings in this map.
*/
public function size() : int
{
return $this->size;
}
/**
* Returns true if this map maps one or more keys to the specified value.
*/
public function containsValue($value) : bool
{
return in_array($this->maskNull($value), $this->values, true);
}
/**
* Returns true if this map contains a mapping for the specified key.
*/
public function containsKey(AbstractEnum $key) : bool
{
$this->checkKeyType($key);
return null !== $this->values[$key->ordinal()];
}
/**
* Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
*
* More formally, if this map contains a mapping from a key to a value, then this method returns the value;
* otherwise it returns null (there can be at most one such mapping).
*
* A return value of null does not necessarily indicate that the map contains no mapping for the key; it's also
* possible that hte map explicitly maps the key to null. The {@see self::containsKey()} operation may be used to
* distinguish these two cases.
*
* @return mixed
*/
public function get(AbstractEnum $key)
{
$this->checkKeyType($key);
return $this->unmaskNull($this->values[$key->ordinal()]);
}
/**
* Associates the specified value with the specified key in this map.
*
* If the map previously contained a mapping for this key, the old value is replaced.
*
* @return mixed the previous value associated with the specified key, or null if there was no mapping for the key.
* (a null return can also indicate that the map previously associated null with the specified key.)
* @throws IllegalArgumentException when the passed values does not match the internal value type
*/
public function put(AbstractEnum $key, $value)
{
$this->checkKeyType($key);
if (! $this->isValidValue($value)) {
throw new IllegalArgumentException(sprintf('Value is not of type %s', $this->valueType));
}
$index = $key->ordinal();
$oldValue = $this->values[$index];
$this->values[$index] = $this->maskNull($value);
if (null === $oldValue) {
++$this->size;
}
return $this->unmaskNull($oldValue);
}
/**
* Removes the mapping for this key frm this map if present.
*
* @return mixed the previous value associated with the specified key, or null if there was no mapping for the key.
* (a null return can also indicate that the map previously associated null with the specified key.)
*/
public function remove(AbstractEnum $key)
{
$this->checkKeyType($key);
$index = $key->ordinal();
$oldValue = $this->values[$index];
$this->values[$index] = null;
if (null !== $oldValue) {
--$this->size;
}
return $this->unmaskNull($oldValue);
}
/**
* Removes all mappings from this map.
*/
public function clear() : void
{
$this->values = array_fill(0, count($this->keyUniverse), null);
$this->size = 0;
}
/**
* Compares the specified map with this map for quality.
*
* Returns true if the two maps represent the same mappings.
*/
public function equals(self $other) : bool
{
if ($this === $other) {
return true;
}
if ($this->size !== $other->size) {
return false;
}
return $this->values === $other->values;
}
/**
* Returns the values contained in this map.
*
* The array will contain the values in the order their corresponding keys appear in the map, which is their natural
* order (the order in which the num constants are declared).
*/
public function values() : array
{
return array_values(array_map(function ($value) {
return $this->unmaskNull($value);
}, array_filter($this->values, function ($value) : bool {
return null !== $value;
})));
}
public function serialize() : string
{
$values = [];
foreach ($this->values as $ordinal => $value) {
if (null === $value) {
continue;
}
$values[$ordinal] = $this->unmaskNull($value);
}
return serialize([
'keyType' => $this->keyType,
'valueType' => $this->valueType,
'allowNullValues' => $this->allowNullValues,
'values' => $values,
]);
}
public function unserialize($serialized) : void
{
$data = unserialize($serialized);
$this->__construct($data['keyType'], $data['valueType'], $data['allowNullValues']);
foreach ($this->keyUniverse as $key) {
if (array_key_exists($key->ordinal(), $data['values'])) {
$this->put($key, $data['values'][$key->ordinal()]);
}
}
}
public function getIterator() : Traversable
{
foreach ($this->keyUniverse as $key) {
if (null === $this->values[$key->ordinal()]) {
continue;
}
yield $key => $this->unmaskNull($this->values[$key->ordinal()]);
}
}
private function maskNull($value)
{
if (null === $value) {
return NullValue::instance();
}
return $value;
}
private function unmaskNull($value)
{
if ($value instanceof NullValue) {
return null;
}
return $value;
}
/**
* @throws IllegalArgumentException when the passed key does not match the internal key type
*/
private function checkKeyType(AbstractEnum $key) : void
{
if (get_class($key) !== $this->keyType) {
throw new IllegalArgumentException(sprintf(
'Object of type %s is not the same type as %s',
get_class($key),
$this->keyType
));
}
}
private function isValidValue($value) : bool
{
if (null === $value) {
if ($this->allowNullValues) {
return true;
}
return false;
}
switch ($this->valueType) {
case 'mixed':
return true;
case 'bool':
case 'boolean':
return is_bool($value);
case 'int':
case 'integer':
return is_int($value);
case 'float':
case 'double':
return is_float($value);
case 'string':
return is_string($value);
case 'object':
return is_object($value);
case 'array':
return is_array($value);
}
return $value instanceof $this->valueType;
}
}

View file

@ -1,10 +0,0 @@
<?php
declare(strict_types = 1);
namespace DASPRiD\Enum\Exception;
use Exception;
final class CloneNotSupportedException extends Exception implements ExceptionInterface
{
}

View file

@ -1,10 +0,0 @@
<?php
declare(strict_types = 1);
namespace DASPRiD\Enum\Exception;
use Throwable;
interface ExceptionInterface extends Throwable
{
}

View file

@ -1,10 +0,0 @@
<?php
declare(strict_types = 1);
namespace DASPRiD\Enum\Exception;
use Exception;
final class ExpectationException extends Exception implements ExceptionInterface
{
}

View file

@ -1,10 +0,0 @@
<?php
declare(strict_types = 1);
namespace DASPRiD\Enum\Exception;
use Exception;
final class IllegalArgumentException extends Exception implements ExceptionInterface
{
}

View file

@ -1,10 +0,0 @@
<?php
declare(strict_types = 1);
namespace DASPRiD\Enum\Exception;
use Exception;
final class MismatchException extends Exception implements ExceptionInterface
{
}

View file

@ -1,10 +0,0 @@
<?php
declare(strict_types = 1);
namespace DASPRiD\Enum\Exception;
use Exception;
final class SerializeNotSupportedException extends Exception implements ExceptionInterface
{
}

View file

@ -1,10 +0,0 @@
<?php
declare(strict_types = 1);
namespace DASPRiD\Enum\Exception;
use Exception;
final class UnserializeNotSupportedException extends Exception implements ExceptionInterface
{
}

View file

@ -1,55 +0,0 @@
<?php
declare(strict_types = 1);
namespace DASPRiD\Enum;
use DASPRiD\Enum\Exception\CloneNotSupportedException;
use DASPRiD\Enum\Exception\SerializeNotSupportedException;
use DASPRiD\Enum\Exception\UnserializeNotSupportedException;
final class NullValue
{
/**
* @var self
*/
private static $instance;
private function __construct()
{
}
public static function instance() : self
{
return self::$instance ?: self::$instance = new self();
}
/**
* Forbid cloning enums.
*
* @throws CloneNotSupportedException
*/
final public function __clone()
{
throw new CloneNotSupportedException();
}
/**
* Forbid serializing enums.
*
* @throws SerializeNotSupportedException
*/
final public function __sleep() : array
{
throw new SerializeNotSupportedException();
}
/**
* Forbid unserializing enums.
*
* @throws UnserializeNotSupportedException
*/
final public function __wakeup() : void
{
throw new UnserializeNotSupportedException();
}
}