framjet / enum-bitmask
A small library that provides functionality to PHP 8.1 enums to act as BitMask flags
Requires
- php: ~8.1.0
Requires (Dev)
- framjet/coding-standard: ^1.0
- phpunit/phpunit: ^9.5.10
- psalm/plugin-phpunit: ^0.16.1
- roave/infection-static-analysis-plugin: ^1.12
- squizlabs/php_codesniffer: ^3.6.2
- vimeo/psalm: ^4.15.0
README
A small library that provides functionality to PHP 8.1 enums to act as BitMask flags.
Why?
Sometimes you need some flags on the objects, to represent some features, most often its used simple property with the
type of
bool
but then you start making several properties and then your object size (Serialized/JSON) starts growing quite a
lot.
The most efficient storage option for flags was always bitmask value. It provides up to 32 unique flags inside a single
int32
value.
Another big benefit is the ability to make AND
, OR
, NOT
operations in one call instead of doing many if
expressions to check all those property values.
Install
Via Composer
$ composer require framjet/enum-bitmask
Usage
The library provides a trait BitmaskFunctionality
which is needed to include inside
int backed enum.
Here is a tiny example of using Enum
to provide flags using space-efficient bitmask int value:
<?php use FramJet\Packages\EnumBitmask\BitmaskFunctionality; enum Flag: int { use BitmaskFunctionality; case Public = 0b000001; case Protected = 0b000010; case Private = 0b000100; case ReadOnly = 0b001000; case Static = 0b010000; case Final = 0b100000; } class Member { public function __construct(private int $flags = 0) { } public function setPublic(): void { $this->flags = Flag::set( Flag::clear($this->flags, Flag::Private, Flag::Protected), Flag::Public ); } public function isPublic(): bool { return Flag::on($this->flags, Flag::Public); } public function isReadOnly(): bool { return Flag::on($this->flags, Flag::ReadOnly); } /** @return list<Flag> */ public function getFlags(): array { return Flag::parse($this->flags); } public function getFlagsValue(): int { return $this->flags; } } class Container { /** @param list<Member> $members */ public function __construct(private array $members = []) { } public function addMember(Member $member): void { $this->members[] = $member; } public function getMembers(Flag ...$flags): array { return array_filter($this->members, static fn(Member $m) => Flag::any($m->getFlagsValue(), ...$flags)); } } $memberPublic = new Member(); $memberPublic->setPublic(); $memberPublic->getFlags(); // [Flag::Public] $memberReadOnly = new Member(Flag::build(Flag::ReadOnly)); $memberReadOnly->isReadOnly(); // true $memberReadOnly->isPublic(); // false $memberPrivate = new Member(Flag::build(Flag::Private, Flag::ReadOnly)); $memberPrivate->isReadOnly(); // true $memberPrivate->isPublic(); // false $memberPrivate->getFlags(); // [Flag::Private, Flag::ReadOnly] array_map( static fn(Flag $f) => $f->toString(), $memberPrivate->getFlags() ); // ['0b0000_0000_0000_0000_0000_0000_0000_0100', '0b0000_0000_0000_0000_0000_0000_0000_1000'] $container = new Container(); $container->addMember($memberPublic); $container->addMember($memberReadOnly); $container->addMember($memberPrivate); $container->getMembers(); // [$memberPublic, $memberReadOnly, $memberPrivate] $container->getMembers(Flag::Public); // [$memberPublic] $container->getMembers(Flag::ReadOnly); // [$memberReadOnly, $memberPrivate] $container->getMembers(Flag::ReadOnly, Flag::Public); // [$memberPublic, $memberReadOnly, $memberPrivate]
License
Please see License File for more information.