With Phlags you can declare flagable enums to provide types with varying and multiple states. While depending on binary operations Phlags provides high performance and reliabilty.
Install the latest version with
$ composer require codekandis/phlags
Example: Simple permissions in a file system
Declare a class extending the flagable base class AbstractFlagable
.
class Permissions extends AbstractFlagable
{
public const int READ = 1;
public const int WRITE = 2;
public const int EXECUTE = 4;
}
In the context of manipulating the flagable the following values are supposed to be equal and can similarly passed to all methods of the flagable.
1
Permissions::READ
new Permissions( 1 )
new Permissions( Permission::READ )
new Permissions( 'READ' );
In the other hand the type restriction of PHP does not allow any combination of an integer value with a string with a flagable.
new Permission( 1 | 'READ' | new Permissions( READ ) )
You can easily instantiate your flagable in different ways.
// with the default flag 'Permissions::NONE' (inherited from `FlagableInterface::NONE`)
$permissions = new Permissions();
// with a single flag
$permissions = new Permissions( Permissions::READ );
// with multiple flags
$permissions = new Permissions( Permissions::READ | Permissions::WRITE );
// with another flagable
$permissions = new Permissions( new Permissions( Permissions::READ ) );
// with string representations
$permissions = new ( 'READ' );
$permissions = new ( 'READ|WRITE' );
$permissions = new ( 'READ|WRITE|EXECUTE' );
// with mixed string representations
$permissions = new ( '1' );
$permissions = new ( '1|2' );
$permissions = new ( '1|WRITE|4' );
You can read the value of the flagable in 2 different ways.
$permissions = new Permissions( Permissions::READ );
echo $permissions->getValue(); // 1
echo $permissions(); // 1
You can determine if one or more specific flags have been set.
$permissions = new Permissions( Permissions::READ | Permissions::WRITE );
$permissions->has( Permissions::READ ); // true
$permissions->has( Permissions::WRITE ); // true
$permissions->has( Permissions::EXECUTE ); // false
You can set, unset and switch flags.
$permissions = new Permissions();
$permissions->set( Permissions::READ );
$permissions->unset( Permissions::READ );
$permissions->switch( Permissions::READ );
$permissions->has( Permissions::READ ); // true
The base class AbstractFlagable
implements the fluent interface. So the manipulation of the flagable can be chained.
$permissions = new Permissions();
$permissions->set( Permissions::READ )
->unset( Permissions::READ )
->switch( Permissions::READ )
->has( Permissions::READ ); // true
A flagable can stringified in different ways with different outputs.
$permissions = new Permissions();
(string)$permissions->getValue(); // 0
(string)$permissions(); // 0
(string)$permissions; // NONE
$permissions->__toString(); // NONE
$permissions = new Permissions( PERMISSIONS::READ | PERMISSIONS::EXECUTE );
(string)$permissions->getValue(); // 5
(string)$permissions(); // 5
(string)$permissions; // READ|EXECUTE
$permissions->__toString(); // READ|EXECUTE
To keep the simplicity and performance Phlags provides Traitful Extensions
. Instead of implementing a complex and heavyweight inheritance you can combine the extensions of your choice into the flagable of your needs.
class Permissions extends AbstractFlagable SomeTraitfulInterface
{
use SomeTraitfulExtension;
public const int READ = 1;
public const int WRITE = 2;
public const int EXECUTE = 4;
}
— ConditionalManipulationExtension
The Conditional Manipulation provides you with methods to set, unset and switch a flag value while a passed statement must evaluate to true.
$pathToFile = '/some-random-file.txt';
$permissions = new Permissions();
$permissions->ifSet( Permissions::DIRECTORY, is_dir( $pathToFile ) );
$permissions->has( Permissions::DIRECTORY ); // false
$pathToFile = '/some-random-directory';
$permissions = new Permissions();
$permissions->ifSet( Permissions::DIRECTORY, is_dir( $pathToDirectory ) );
$permissions->has( Permissions::DIRECTORY ); // true
While instantiating your very first flagable your flagable has to pass a one-time validation.
- all declared constants are an
unsigned integer
- all constants are a power of 2
- there is no duplicates of any of the constant values
- there is no missing values, e. g. a flagable with a flags set
1, 2, 8
ist invalid, while the flag4
is missing
If the flagable does not pass the validation an InvalidFlagableException
will be thrown and you can retreive an array of detailed error messages of the validation.
try
{
$permissions = new Permissions();
}
catch ( InvalidFlagableException $e )
{
$errorMessages = $e->getErrorMessages();
}
A flag value passed to the methods of the flagable has to pass a validation on every method call.
- it is an
unsigned integer
less or equal than the maximum value of the called flagable - it is a
string
representation of a flagable with an identic type as the type of the called flagable - it is a flagable with an identic type as the type of the called flagable
- it does not exceeds the maximum flag value of the called flagable
If the value does not pass the validation an InvalidValueException
will be thrown and you can retreive an array of detailed error messages of the validation.
try
{
$permissions->set( $value );
}
catch ( InvalidValueException $e )
{
$errorMessages = $e->getErrorMessages();
}