Skip to content

Commit

Permalink
Converting enum to only allow singleton
Browse files Browse the repository at this point in the history
Signed-off-by: Nate Brunette <n@tebru.net>
  • Loading branch information
natebrunette committed Jan 5, 2017
1 parent 97252ce commit 8ece481
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 52 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
Enum
====

A simple PHP library to add support for enums. This requires more work than myclabs/php-enum, but does not require reflection.
A simple PHP library to add support for enums. This requires slightly
more work than myclabs/php-enum, but does not require reflection. It
also forces enums to be singletons.

Installation
------------
Expand Down Expand Up @@ -41,9 +43,8 @@ To use, extend `AbstractEnum` and implement the getConstants() method.
}
}

Now you can create a new instance normally or using the static method.
Now you can create a new instance using the static method.

new DirectionEnum('north');
DirectionEnum::create('north');

You can also create an instance using the __callStatic magic method.
Expand All @@ -66,9 +67,10 @@ Reference

There are multiple methods available on each enum

* `create()` [static] Returns an instance of the enum
* `values()` [static] A 0-indexed array of all of the enum values
* `exists($value)` [static] Returns true if the value exists
* `toArray()` [static] Returns a hash with keys and values as the enum values
* `equals($enum)` Performs a non-strict comparison of two enums or value comparison of a string
* `equals($enum)` Performs a strict comparison of two enum values
* `getValue()` Returns the current value of the enum
* `__toString()` Same as `getValue()`
45 changes: 30 additions & 15 deletions src/AbstractEnum.php
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
<?php
/*
* Copyright (c) 2015 Nate Brunette.
* Copyright (c) Nate Brunette.
* Distributed under the MIT License (http://opensource.org/licenses/MIT)
*/

namespace Tebru\Enum;

use ArrayIterator;
use BadMethodCallException;
use IteratorAggregate;
use RuntimeException;

/**
/**v
* Class AbstractEnum
*
* @author Nate Brunette <n@tebru.ent>
Expand All @@ -22,12 +23,20 @@ abstract class AbstractEnum implements EnumInterface, IteratorAggregate
*/
private $value;

/**
* An array of created instances to ensure singleton
*
* @var array
*/
private static $instances = [];

/**
* Constructor
*
* @param string $value
* @throws RuntimeException If the value is not valid
*/
public function __construct($value)
final private function __construct($value)
{
if (!static::exists($value)) {
throw new RuntimeException(sprintf('%s is not a valid value for this enum.', $value));
Expand All @@ -49,27 +58,31 @@ public function __toString()
/**
* Do a comparison to check if the enums are non-strictly equal
*
* @param AbstractEnum|string $value
* @param AbstractEnum $enum
* @return bool
*/
public function equals($value)
public function equals(AbstractEnum $enum)
{
if ($value instanceof AbstractEnum) {
return $this == $value;
}

return $this->value === $value;
return $this->getValue() === $enum->getValue();
}

/**
* Create a new instance of the enum
*
* @param string $value
* @return $this
* @return AbstractEnum
* @throws RuntimeException If the value is not valid
*/
public static function create($value)
{
return new static($value);
if (array_key_exists($value, self::$instances)) {
return self::$instances[$value];
}

$instance = new static($value);
self::$instances[$value] = $instance;

return $instance;
}

/**
Expand Down Expand Up @@ -119,16 +132,18 @@ public function getValue()
* @param string $name
* @param $arguments
* @return static
* @throws RuntimeException If the value is not valid
* @throws BadMethodCallException If the constant doesn't exist in the class
*/
public static function __callStatic($name, $arguments)
{
$constant = @constant(sprintf('static::%s', $name));
$constant = @constant('static::' . $name);

if (null === $constant) {
throw new \BadMethodCallException(sprintf('Could not find constant "%s" for class "%s"', $name, static::class));
throw new BadMethodCallException(sprintf('Could not find constant "%s" for class "%s"', $name, static::class));
}

return new static($constant);
return self::create($constant);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/EnumInterface.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php
/*
* Copyright (c) 2015 Nate Brunette.
* Copyright (c) Nate Brunette.
* Distributed under the MIT License (http://opensource.org/licenses/MIT)
*/

Expand Down
54 changes: 23 additions & 31 deletions tests/EnumTest.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php
/*
* Copyright (c) 2015 Nate Brunette.
* Copyright (c) Nate Brunette.
* Distributed under the MIT License (http://opensource.org/licenses/MIT)
*/

Expand All @@ -21,16 +21,16 @@ class EnumTest extends PHPUnit_Framework_TestCase
*/
public function testConstructorWillThrowException()
{
new MockDirectionEnum('foo');
MockDirectionEnum::create('foo');
}

/**
* @dataProvider getDirections
*/
public function testCreateEnum($direction)
{
$enum = new MockDirectionEnum($direction);
$this->assertInstanceOf(MockDirectionEnum::class, $enum);
$enum = MockDirectionEnum::create($direction);
$this->assertSame($direction, $enum->getValue());
}

/**
Expand All @@ -39,12 +39,13 @@ public function testCreateEnum($direction)
public function testCreateEnumStaticMethod($direction)
{
$enum = MockDirectionEnum::create($direction);
$this->assertInstanceOf(MockDirectionEnum::class, $enum);
$this->assertSame($direction, $enum->getValue());
}

public function testCreateEnumMagicMethod()
{
$this->assertInstanceOf(MockDirectionEnum::class, MockDirectionEnum::EAST());
$enum = MockDirectionEnum::EAST();
$this->assertSame(MockDirectionEnum::EAST, $enum->getValue());
}

/**
Expand All @@ -61,7 +62,7 @@ public function testCreateEnumMagicMethodException()
*/
public function testEnumToString($direction)
{
$enum = new MockDirectionEnum($direction);
$enum = MockDirectionEnum::create($direction);
$this->assertSame($direction, (string)$enum);
}

Expand All @@ -70,39 +71,30 @@ public function testEnumToString($direction)
*/
public function testEqualsEnum($direction)
{
$enum = new MockDirectionEnum($direction);
$enumCompare = new MockDirectionEnum($direction);
$enum = MockDirectionEnum::create($direction);
$enumCompare = MockDirectionEnum::create($direction);
$this->assertTrue($enum->equals($enumCompare));
}

/**
* @dataProvider getDirections
*/
public function testEqualsString($direction)
{
$enum = new MockDirectionEnum($direction);
$enumCompare = new MockDirectionEnum($direction);
$this->assertTrue($enum->equals($enumCompare->getValue()));
}

public function testNotEqualsEnum()
{
$enum = new MockDirectionEnum('north');
$enumCompare = new MockDirectionEnum('south');
$enum = MockDirectionEnum::create('north');
$enumCompare = MockDirectionEnum::create('south');
$this->assertFalse($enum->equals($enumCompare));
}

public function testNotEqualsString()
public function testStrictlyEqual()
{
$enum = new MockDirectionEnum('north');
$this->assertFalse($enum->equals(MockDirectionEnum::SOUTH));
$enum = MockDirectionEnum::create('north');
$enumCompare = MockDirectionEnum::create('north');
$this->assertSame($enum, $enumCompare);
}

public function testNotStrictlyEqual()
public function testStrictlyEqualCreateAndCallStatic()
{
$enum = new MockDirectionEnum('north');
$enumCompare = new MockDirectionEnum('north');
$this->assertFalse($enum === $enumCompare);
$enum = MockDirectionEnum::create('north');
$enumCompare = MockDirectionEnum::NORTH();
$this->assertSame($enum, $enumCompare);
}

/**
Expand All @@ -123,7 +115,7 @@ public function testGetValues()
*/
public function testGetValue($direction)
{
$enum = new MockDirectionEnum($direction);
$enum = MockDirectionEnum::create($direction);
$this->assertSame($direction, $enum->getValue());
}

Expand All @@ -137,9 +129,9 @@ public function testToArray()
*/
public function testCanIterate($direction)
{
$enum = new MockDirectionEnum($direction);
$enum = MockDirectionEnum::create($direction);
foreach ($enum as $value) {
$this->assertTrue($enum->exists($value));
$this->assertTrue($enum::exists($value));
}
}

Expand Down
2 changes: 1 addition & 1 deletion tests/Mock/MockDirectionEnum.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php
/*
* Copyright (c) 2015 Nate Brunette.
* Copyright (c) Nate Brunette.
* Distributed under the MIT License (http://opensource.org/licenses/MIT)
*/

Expand Down

0 comments on commit 8ece481

Please sign in to comment.