Flags for PHP


In my last post I wrote about the enumerated type (Enum) for PHP. In C# an Enum can have multiple values when it has the [Flags] attribute. A flags enum can be seen as a bitwise mask which can be used to combine boolean properties of an entity into one single integer property. This might come in handy when filtering on these properties. In this article I show my implementation for a flags enum in PHP and demonstrate the use of it in an example.

A car parking can be limited to allow only vehiles of a certain type use the parking. This can be modelled using an enum:

Class VehicleTypes extends Enum {
      const Sedan = 1;
      const Station = 2;
      const Mpv = 3;
      const Truck = 4;
      const Bike = 5;
      const Cabrio= 6;
}
 
$parking = new Parking();
 
$parking->allowedType = VehicleTypes::Bike();

However this way a car parking can only allow one type of vehicles to use the parking. If you want to enable the parking to allow more types of vehicles you’ll have to use boolean properties, one for each type, on the parking:

$parking = new Parking();
 
$parking->allowSedan = true;
 
$parking->allowBike = true;

Adding a new vehicle type would imply significant modification to the code: you need to extend the Parking class for each type you want to add and everywhere you check or set the types on a parking object you’ll need to modify the code to take these booleans into account. Flags offer a rather simple solution to this problem:

Class VehicleTypes extends Flags {
      const Sedan = 1;
      const Station = 2;
      const Mpv = 4;
      const Truck = 8;
      const Bike = 16;
      const Truck = 32;
}
 
$parking = new Parking();
 
$parking->allowedTypes = CarTypes::Bike()->Add(CarType::Sedan());

Internally $parking doesn’t have single boolean properties, but it specifies a single integer which holds all the properties. Notice how this definition of VehicleTypes differs from the first time VehicleTypes was defined. It now extends Flags instead of Enum and instead of incrementing each value by 1 each value is incremented by a power of 2.

The flags VehicleTypes now has the internal value 17 (1 = Sedan, 16 = Bike). Bitwise 17 is represented as 10001. So instead of defining five separate booleans for each type, a bitwise representation for all types is used in an integer.

As you can print values of an Enum type, Flags can be printed too. Using the $parking from the last example, when echoing $parking as done below it results in the following output:

echo $parking->allowedTypes; // echoes "Sedan|Bike"
 
echo $parking->allowedTypes(); // echoes 17

Using it to determine whether or not a Flags type variable has a certain flag set or not you could use the following:

$parking->hasAny(VehicleTypes::Sedan()); //true

or short:

$parking->has(VehicleTypes::Sedan()); // true

And a check if a flags has all of another flags set to true:

$parking->hasAll(VehicleTypes::Sedan()->Add(VehicleTypes::Station)); //false

Remove a flag:

$parking->remove(VehicleTypes::Bike());
 
$parking->has(VehicleTypes::Bike()); // false
 
$parking->has(VehicleTypes::Sedan()); //true

A complete reference can be found at the example page. Just like an example page was included for the enumerated type for PHP.

VN:F [1.3.1_645]
Rating: 0.0/10 (0 votes cast)
  • Share/Save/Bookmark
  1. #1 by Freek - October 23rd, 2013 at 13:29

    Nice, I definitely think PHP has some use for these constructs.

    One suggestion: Make the instances immutable. This would make code using these constructs better maintainable, in my opinion.

(will not be published)
  1. No trackbacks yet.