Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 55 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![Total Downloads](https://poser.pugx.org/marc-mabe/php-enum/downloads.png)](https://packagist.org/packages/marc-mabe/php-enum)
[![Latest Stable](https://poser.pugx.org/marc-mabe/php-enum/v/stable.png)](https://packagist.org/packages/marc-mabe/php-enum)

This is a native PHP implementation to add enumeration support to PHP >= 5.3.
This is a native PHP implementation to add enumeration support to PHP.
It's an abstract class that needs to be extended to use it.


Expand Down Expand Up @@ -204,40 +204,62 @@ But of course this solution has downsides, too:

## EnumSet

An `EnumSet` groups enumerators of the same enumeration type together.
An `EnumSet` is a specialized Set implementation for use with enumeration types.
All of the enumerators in an `EnumSet` must come from a single enumeration type that is specified, when the set is
created.

It implements `Iterator` and `Countable`
so elements can be iterated and counted like a normal array
using `foreach` and `count()`.
Enum sets are represented internally as bit vectors. The bit vektor is eigther an integer type or a binary string type
depending on how many enumerators are defined is the enumeration type. This representation is extremely compact and
efficient. Bulk operations will run very quickly. Enumerators of an `EnumSet` are unique and ordered based on it's
ordinal number by design.

Internally it's based on a bitset. Integer bitset or binary bitset
depending on how many enumerators are defined for the given enumeration.
It implements `IteratorAggregate` and `Countable` to be directly iterable with `foreach` and countable with `count()`.

Enumerators attached to an `EnumSet` are unique and ordered based on it's ordinal number by design.
The `EnumSet` has a mutable and an immutable interface.
Mutable methods starts with `set`, `attach` and `detach`.
Immutable methods starts with `with` or `without`.

```php
use MabeEnum\EnumSet;

// create a new EnumSet
$enumSet = new EnumSet('UserStatus');
// create a new EnumSet and initialize with the given enumerators
$enumSet = new EnumSet('UserStatus', [UserStatus::ACTIVE()]);

// modify an EnumSet (mutable interface)

// attach enumerators (by value or by instance)
$enumSet->attach(UserStatus::INACTIVE);
$enumSet->attach(UserStatus::ACTIVE());
$enumSet->attach(UserStatus::DELETED());
$enumSet->attachEnumerators([UserStatus::INACTIVE, UserStatus::DELETED()]);
// or
$enumSet->attachEnumerator(UserStatus::INACTIVE);
$enumSet->attachEnumerator(UserStatus::DELETED());

// detach enumerators (by value or by instance)
$enumSet->detachEnumerators([UserStatus::INACTIVE, UserStatus::DELETED()]);
// or
$enumSet->detachEnumerator(UserStatus::INACTIVE);
$enumSet->detachEnumerator(UserStatus::DELETED());


// The immutable interface will create a new EnumSet for each modification

// add enumerators (by value or by instance)
$enumSet = $enumSet->withEnumerators([UserStatus::INACTIVE, UserStatus::DELETED()]);
// or
$enumSet = $enumSet->withEnumerator(UserStatus::INACTIVE);
$enumSet = $enumSet->withEnumerator(UserStatus::DELETED());

// detach enumerators (by value or by instance)
$enumSet->detach(UserStatus::INACTIVE);
$enumSet->detach(UserStatus::DELETED());
$enumSet->withoutEnumerators([UserStatus::INACTIVE, UserStatus::DELETED()]);
// or
$enumSet = $enumSet->withEnumerator(UserStatus::INACTIVE);
$enumSet = $enumSet->withEnumerator(UserStatus::DELETED());


// contains enumerators (by value or by instance)
$enumSet->contains(UserStatus::INACTIVE); // bool


// count number of attached enumerations
// count the number of enumerators
$enumSet->count();
count($enumSet);

Expand All @@ -261,12 +283,23 @@ $enumSet->isEqual($other); // Check if the EnumSet is the same as other
$enumSet->isSubset($other); // Check if the EnumSet is a subset of other
$enumSet->isSuperset($other); // Check if the EnumSet is a superset of other

$enumSet->union($other); // Produce a new set with enumerators from both this and other (this | other)
$enumSet->intersect($other); // Produce a new set with enumerators common to both this and other (this & other)
$enumSet->diff($other); // Produce a new set with enumerators in this but not in other (this - other)
$enumSet->symDiff($other); // Produce a new set with enumerators in either this and other but not in both (this ^ other)

// union, intersect, difference and symmetric difference

// ... the mutable interface will modify the set
$enumSet->setUnion($other); // Enumerators from both this and other (this | other)
$enumSet->setIntersect($other); // Enumerators common to both this and other (this & other)
$enumSet->setDiff($other); // Enumerators in this but not in other (this - other)
$enumSet->setSymDiff($other); // Enumerators in either this and other but not in both (this ^ other)

// ... the immutable interface will produce a new set
$enumSet = $enumSet->withUnion($other); // Enumerators from both this and other (this | other)
$enumSet = $enumSet->withIntersect($other); // Enumerators common to both this and other (this & other)
$enumSet = $enumSet->withDiff($other); // Enumerators in this but not in other (this - other)
$enumSet = $enumSet->withSymDiff($other); // Enumerators in either this and other but not in both (this ^ other)
```


## EnumMap

An `EnumMap` maps enumerators of the same type to data assigned to.
Expand Down Expand Up @@ -331,6 +364,7 @@ $enumMap->getKeys();
$enumMap->getValues();
```


## Serializing

Because this enumeration implementation is based on a singleton pattern and in PHP
Expand Down Expand Up @@ -373,6 +407,7 @@ var_dump($north1->is($north2)); // returns TRUE - this way the two instances are
var_dump($north2->is($north1)); // returns TRUE - equality works in both directions
```


# Why not `SplEnum`

* `SplEnum` is not build-in into PHP and requires pecl extension installed.
Expand Down
115 changes: 100 additions & 15 deletions bench/EnumSet32Bench.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,40 +48,105 @@ public function init()
$this->enumerators = Enum32::getEnumerators();

$this->emptySet = new EnumSet(Enum32::class);
$this->fullSet = new EnumSet(Enum32::class);
$this->fullSet = new EnumSet(Enum32::class, $this->enumerators);
}

public function benchAttachEnumerator()
{
foreach ($this->enumerators as $enumerator) {
$this->fullSet->attach($enumerator);
$this->emptySet->attachEnumerator($enumerator);
}
}

public function benchAttachEnumerator()
public function benchWithEnumerator()
{
foreach ($this->enumerators as $enumerator) {
$this->emptySet->attach($enumerator);
$this->emptySet->withEnumerator($enumerator);
}
}

public function benchAttachEnumerators()
{
$this->emptySet->withEnumerators($this->enumerators);
}

public function benchWithEnumerators()
{
$this->emptySet->attachEnumerators($this->enumerators);
}

public function benchWithValue()
{
foreach ($this->values as $value) {
$this->emptySet->withEnumerator($value);
}
}

public function benchAttachValue()
{
foreach ($this->values as $value) {
$this->emptySet->attach($value);
$this->emptySet->attachEnumerator($value);
}
}

public function benchAttachValues()
{
$this->emptySet->attachEnumerators($this->values);
}

public function benchWithValues()
{
$this->emptySet->withEnumerators($this->values);
}

public function benchDetachEnumerator()
{
foreach ($this->enumerators as $enumerator) {
$this->fullSet->detach($enumerator);
$this->fullSet->detachEnumerator($enumerator);
}
}

public function benchWithoutEnumerator()
{
foreach ($this->enumerators as $enumerator) {
$this->fullSet->withoutEnumerator($enumerator);
}
}

public function benchDetachEnumerators()
{
$this->fullSet->detachEnumerators($this->enumerators);
}

public function benchWithoutEnumerators()
{
$this->fullSet->withoutEnumerators($this->enumerators);
}

public function benchDetachValue()
{
foreach ($this->values as $value) {
$this->fullSet->detach($value);
$this->fullSet->detachEnumerator($value);
}
}

public function benchWithoutValue()
{
foreach ($this->values as $value) {
$this->fullSet->withoutEnumerator($value);
}
}

public function benchDetachValues()
{
$this->fullSet->detachEnumerators($this->values);
}

public function benchWithoutValues()
{
$this->fullSet->withoutEnumerators($this->values);
}

public function benchContainsEnumerator()
{
foreach ($this->enumerators as $enumerator) {
Expand Down Expand Up @@ -135,24 +200,44 @@ public function benchIsSuperset()
$this->fullSet->isSuperset($this->fullSet);
}

public function benchUnion()
public function benchSetUnion()
{
$this->fullSet->setUnion($this->emptySet);
}

public function benchWithUnion()
{
$this->fullSet->withUnion($this->emptySet);
}

public function benchSetIntersect()
{
$this->fullSet->setIntersect($this->emptySet);
}

public function benchWithIntersect()
{
$this->fullSet->withIntersect($this->emptySet);
}

public function benchSetDiff()
{
$this->fullSet->union($this->emptySet);
$this->fullSet->setDiff($this->emptySet);
}

public function benchIntersect()
public function benchWithDiff()
{
$this->fullSet->intersect($this->emptySet);
$this->fullSet->withDiff($this->emptySet);
}

public function benchDiff()
public function benchSetSymDiff()
{
$this->fullSet->diff($this->emptySet);
$this->fullSet->setSymDiff($this->emptySet);
}

public function benchSymDiff()
public function benchWithSymDiff()
{
$this->fullSet->symDiff($this->emptySet);
$this->fullSet->withSymDiff($this->emptySet);
}

public function benchGetOrdinalsFull()
Expand Down
Loading