Commit 4c66fedf authored by Jan Kuchař's avatar Jan Kuchař

Merge branch 'support-for-non-strict-comparision' into 'master'

feature: support for non-strict comparision

See merge request !4
parents 84c38d31 9bf343cb
Pipeline #14366 passed with stages
in 31 seconds
......@@ -7,11 +7,14 @@ trait AutoInstances
// todo: better define this interface
abstract protected static function getConstantToScalar(): array;
/** @param string|int $scalar */
abstract public function __construct($scalar);
protected static function provideInstances(): array
{
$instances = [];
foreach (static::getConstantToScalar() as $constantName => $primitiveValue) {
$instances[$primitiveValue] = new static();
$instances[] = new static($primitiveValue);
}
return $instances;
}
......
......@@ -15,9 +15,6 @@ use Grifart\Enum\Internal\Meta;
*/
abstract class Enum
{
protected function __construct()
{
}
/**
* Provide values for given enum, never call this method directly.
......@@ -102,25 +99,40 @@ abstract class Enum
return $ref->getName();
}
// -------- INSTANCE IMPLEMENTATION ---------
/** @var int|string */
private $scalar;
/**
* @param int|string $scalar
*/
protected function __construct($scalar)
{
$this->scalar = $scalar;
}
/**
* Provides scalar representation of enum value.
* @return int|string
*/
public function getScalarValue()
public function getScalar()
{
return self::getMeta()->getScalarForValue($this);
return $this->scalar;
}
/**
* Retrieves constant name that is used to access enum value.
*
* Note: do not depend on this values, as it can change anytime. This value can be
* @internal Do not depend on this values, as it can change anytime. This value can be
* subject of refactorings of user-defined enums.
*/
public function getConstantName(): string
{
return self::getMeta()->getConstantNameForScalar(
self::getMeta()->getScalarForValue($this)
$this->getScalar()
);
}
......@@ -138,8 +150,8 @@ abstract class Enum
* @param int|string $theOtherScalarValue
* @return bool true if current scalar representation of value equals to given scalar value
*/
public function equalsScalarValue($theOtherScalarValue): bool
public function scalarEquals($theOtherScalarValue): bool
{
return self::getMeta()->getScalarForValue($this) === $theOtherScalarValue;
return $this->getScalar() === $theOtherScalarValue;
}
}
......@@ -9,21 +9,54 @@ final class Meta
{
/** @var string */
private $class;
/** @var array */
/** @var array<string,int|string> */
private $constantToScalar;
/** @var \Grifart\Enum\Enum[] */
/** @var array<int|string,Enum> */
private $scalarToValue;
private function __construct(string $class, array $constantToScalar, array $scalarToValue)
/**
* @param string $class
* @param array<string,string|int> $constantToScalar
* @param Enum[] $values
*/
private function __construct(string $class, array $constantToScalar, array $values)
{
$this->class = $class;
$this->constantToScalar = $constantToScalar;
$this->scalarToValue = $scalarToValue;
$this->scalarToValue = $this->buildScalarToValueMapping($values); // requires constantToScalar to be already set!
}
/**
* @param Enum[] $values
* @return array<string|int,Enum>
*/
private function buildScalarToValueMapping(array $values): array {
$scalarToValues = [];
foreach($values as $value) {
$scalar = $value->getScalar();
if (isset($scalarToValues[$scalar])) {
throw new \LogicException('You have provided duplicated values scalar names.');
}
if(!$this->hasConstantForScalar($scalar)) {
throw new \LogicException("Provided instance contains scalar value '$scalar'. But no corresponding constant of enum was found.");
}
$scalarToValues[$scalar] = $value;
}
return $scalarToValues;
}
public static function from(string $class, array $constantToScalar, array $scalarToValues): self
/**
* @param string $class
* @param array<string,string|int> $constantToScalar
* @param Enum[] $values
* @return self
*/
public static function from(string $class, array $constantToScalar, array $values): self
{
return new self($class, $constantToScalar, $scalarToValues);
return new self($class, $constantToScalar, $values);
}
public function getClass(): string
......@@ -31,18 +64,25 @@ final class Meta
return $this->class;
}
/** @return string[] */
/**
* @return string[]
*/
public function getConstantNames(): array
{
return \array_keys($this->constantToScalar);
}
/**
* @return string[]|int[]
*/
public function getScalarValues(): array
{
return \array_values($this->constantToScalar);
}
/** @return \Grifart\Enum\Enum[] */
/**
* @return Enum[]
*/
public function getValues(): array
{
return \array_values($this->scalarToValue);
......@@ -76,7 +116,7 @@ final class Meta
{
$result = \array_search($scalarValue, $this->constantToScalar, true);
if ($result === false) {
throw new \RuntimeException("Could not find constant name for $scalarValue.");
throw new \LogicException("Could not find constant name for $scalarValue.");
}
return $result;
}
......@@ -88,7 +128,7 @@ final class Meta
{
$result = \array_search($enum, $this->scalarToValue, true);
if ($result === false) {
throw new \RuntimeException("Could not find scalar value given value.");
throw new \LogicException("Could not find scalar value given value.");
}
return $result;
}
......@@ -104,4 +144,12 @@ final class Meta
}
return $this->scalarToValue[$scalar];
}
/**
* @param string|int $scalar
*/
private function hasConstantForScalar($scalar): bool
{
return \in_array($scalar, $this->constantToScalar, TRUE);
}
}
......@@ -23,5 +23,5 @@ class OrderState extends \Grifart\Enum\Enum
\Tester\Assert::notSame(OrderState::NEW(), OrderState::DELIVERED());
\Tester\Assert::notSame(OrderState::ACTIVE(), OrderState::DELIVERED());
\Tester\Assert::same('active', OrderState::ACTIVE()->getScalarValue());
\Tester\Assert::same('active', OrderState::ACTIVE()->getScalar());
\Tester\Assert::same(OrderState::ACTIVE(), OrderState::fromScalar('active'));
......@@ -17,5 +17,5 @@ class EqualsState extends \Grifart\Enum\Enum
\Tester\Assert::true(EqualsState::NEW()->equals(EqualsState::NEW()));
\Tester\Assert::false(EqualsState::NEW()->equals(EqualsState::ACTIVE()));
\Tester\Assert::true(EqualsState::NEW()->equalsScalarValue('new'));
\Tester\Assert::false(EqualsState::NEW()->equalsScalarValue('active'));
\Tester\Assert::true(EqualsState::NEW()->scalarEquals('new'));
\Tester\Assert::false(EqualsState::NEW()->scalarEquals('active'));
<?php
declare(strict_types=1);
require __DIR__ . '/../bootstrap.php';
/**
* @method static Enum1 VALUE1()
* @method static Enum1 VALUE2()
*/
class Enum1 extends \Grifart\Enum\Enum
{
use Grifart\Enum\AutoInstances;
protected const VALUE1 = 'value1';
protected const VALUE2 = 'value2';
}
$val1 = Enum1::VALUE1();
$val2 = Enum1::VALUE2();
/** intentionally non-strict @noinspection TypeUnsafeComparisonInspection PhpNonStrictObjectEqualityInspection */
\Tester\Assert::true($val1 == Enum1::VALUE1());
/** intentionally non-strict @noinspection TypeUnsafeComparisonInspection PhpNonStrictObjectEqualityInspection */
\Tester\Assert::true($val2 == Enum1::VALUE2());
/** intentionally non-strict @noinspection TypeUnsafeComparisonInspection PhpNonStrictObjectEqualityInspection */
\Tester\Assert::true($val1 != Enum1::VALUE2());
/** intentionally non-strict @noinspection TypeUnsafeComparisonInspection PhpNonStrictObjectEqualityInspection */
\Tester\Assert::true($val2 != Enum1::VALUE1());
$switchResult = 0;
switch ($val1) {
case Enum1::VALUE1():
$switchResult = 1;
break;
case Enum1::VALUE2():
$switchResult = 2;
break;
default:
$switchResult = 3;
break;
}
\Tester\Assert::same(1, $switchResult);
......@@ -16,14 +16,14 @@ abstract class StateMachine extends \Grifart\Enum\Enum
protected static function provideInstances(): array
{
return [
self::STATE_A => new class extends StateMachine
new class(self::STATE_A) extends StateMachine
{
public function canDoTransitionTo(StateMachine $targetState): bool
{
return $targetState === StateMachine::STATE_B();
}
},
self::STATE_B => new class extends StateMachine
new class(self::STATE_B) extends StateMachine
{
public function canDoTransitionTo(StateMachine $targetState): bool
{
......
<?php
declare(strict_types=1);
require __DIR__ . '/../bootstrap.php';
/**
* @method static Enum1 VALUE1()
* @method static Enum1 VALUE2()
*/
class Enum1 extends \Grifart\Enum\Enum
{
use Grifart\Enum\AutoInstances;
protected const VALUE1 = 'value1';
protected const VALUE2 = 'value2';
}
$val1 = Enum1::VALUE1();
$val2 = Enum1::VALUE2();
\Tester\Assert::true($val1 === Enum1::VALUE1());
\Tester\Assert::true($val2 === Enum1::VALUE2());
\Tester\Assert::true($val1 !== Enum1::VALUE2());
\Tester\Assert::true($val2 !== Enum1::VALUE1());
......@@ -13,13 +13,12 @@ require __DIR__ . '/../bootstrap.php';
class MissingInstanceEnum extends \Grifart\Enum\Enum
{
protected const STATE_A = 'a';
protected const STATE_B = 'b';
protected static function provideInstances(): array
{
return [
self::STATE_A => new class extends MissingInstanceEnum
new class(self::STATE_A) extends MissingInstanceEnum
{
},
];
......
......@@ -23,11 +23,11 @@ abstract class ReflectionConstantNames2 extends \Grifart\Enum\Enum
protected static function provideInstances(): array
{
return [
self::NEW => new class extends ReflectionConstantNames2 {},
self::ACTIVE => new class extends ReflectionConstantNames2 {},
new class(self::NEW) extends ReflectionConstantNames2 {},
new class(self::ACTIVE) extends ReflectionConstantNames2 {},
];
}
}
\Tester\Assert::same('new', ReflectionConstantNames2::NEW()->getScalarValue());
\Tester\Assert::same('active', ReflectionConstantNames2::ACTIVE()->getScalarValue());
\Tester\Assert::same('new', ReflectionConstantNames2::NEW()->getScalar());
\Tester\Assert::same('active', ReflectionConstantNames2::ACTIVE()->getScalar());
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment