Installation:
composer require reinder83/binary-flags
Basic Usage:
use Reinder83\BinaryFlags\BinaryFlags;
$flags = new BinaryFlags();
$flags->setFlag(1); // Set flag 1
$flags->toggleFlag(2); // Toggle flag 2 (sets it)
$flags->unsetFlag(3); // Unset flag 3 (does nothing if not set)
if ($flags->hasFlag(1)) {
// Flag 1 is set
}
Database Storage:
UNSIGNED BIGINT in MySQL (or equivalent in other DBs).$flags->fromInt($storedValue); // Load from DB
$storedValue = $flags->toInt(); // Save to DB
First Use Case:
use Reinder83\BinaryFlags\Traits\InteractsWithNumericFlags;
class User extends Model
{
use InteractsWithNumericFlags;
protected $flags = [];
}
use Reinder83\BinaryFlags\Traits\InteractsWithNumericFlags;
class Post extends Model
{
use InteractsWithNumericFlags;
protected $flags = [
'is_published' => 1,
'is_featured' => 2,
'is_archived' => 4,
];
public function publish()
{
$this->setFlag('is_published');
$this->save();
}
}
use Reinder83\BinaryFlags\BinaryEnumFlags;
enum PostStatus: int
{
PUBLISHED = 1,
DRAFT = 2,
ARCHIVED = 4;
}
$flags = new BinaryEnumFlags(PostStatus::PUBLISHED);
$flags->toggleFlag(PostStatus::ARCHIVED);
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('flags')->default(0);
// ...
});
$publishedPosts = Post::where('flags', '>=', 1)->get();
// Or use a query scope:
$posts->whereHasFlag('is_published');
$mask = $flags->getMask(['is_published', 'is_featured']);
$flags->setFlags($mask); // Set multiple flags at once
if ($flags->hasAnyFlag([1, 2])) {
// At least one of flag 1 or 2 is set
}
public function rules()
{
return [
'flags' => ['required', 'integer', function ($attribute, $value, $fail) {
$flags = new BinaryFlags($value);
if (!$flags->hasFlag(1) && !$flags->hasFlag(2)) {
$fail('At least one permission flag is required.');
}
}],
];
}
public function getFlagsAttribute($value)
{
return (new BinaryFlags($value))->toArray($this->flags);
}
public function setFlagsAttribute($value)
{
$this->attributes['flags'] = (new BinaryFlags())->fromArray($value)->toInt();
}
protected $appends = ['flags'];
public function getFlagsAttribute()
{
return (new BinaryFlags($this->attributes['flags']))->toArray($this->flags);
}
$factory->define(Post::class, function (Faker $faker) {
return [
'flags' => (new BinaryFlags())->setFlag(1)->toInt(),
];
});
Bit Depth Limitations:
1 to 2^32-1).1 to 2^64-1).if ($flag > (PHP_INT_MAX >> 1)) {
throw new \InvalidArgumentException('Flag exceeds system bit depth.');
}
Floating-Point Deprecation:
float values (e.g., 1.0 instead of 1). Use int explicitly.$flags->setFlag((int) $request->input('flag'));
Database Collisions:
UNSIGNED BIGINT is used (not INT or SMALLINT).$table->unsignedBigInteger('flags')->default(0);
Trait Conflicts:
flags property/methods.use InteractsWithNumericFlags as BinaryFlagsTrait;
Enum Pitfalls:
Bitmaskable or use BinaryEnumFlags:
enum Status implements Bitmaskable {
ACTIVE = 1;
// ...
}
Flag Visualization:
\Log::debug('Flags binary:', [
'value' => $flags->toInt(),
'binary' => decbin($flags->toInt()),
]);
Common Issues:
1 and 1 << 0 are the same).1 << $index for dynamic flags.$flags->reset();
Performance:
setFlags()) are faster than individual setFlag() calls.hasFlag() in loops; cache results if checking repeatedly.Custom Storage:
BinaryFlags to support alternative storage (e.g., Redis):
class RedisBinaryFlags extends BinaryFlags
{
public function __construct($key, $initialValue = 0)
{
$this->key = $key;
$this->fromInt($initialValue);
}
public function toInt()
{
return (int) Redis::get($this->key);
}
public function save()
{
Redis::set($this->key, $this->toInt());
}
}
Validation Rules:
use Reinder83\BinaryFlags\BinaryFlags;
class FlagsRule extends Rule
{
public function passes($attribute, $value)
{
$flags = new BinaryFlags($value);
return $flags->hasFlag(1) || $flags->hasFlag(2);
}
}
Query Builder Extensions:
public function scopeHasFlag(Builder $query, string $flagName)
{
return $query->where('flags', '>=', $this->flags[$flagName]);
}
Event Triggers:
use Reinder83\BinaryFlags\Traits\InteractsWithNumericFlags;
class User extends Model
{
use InteractsWithNumericFlags;
protected $flags = ['is_admin' => 1];
protected static function booted()
{
static::saved(function ($model) {
if ($model->wasChanged('flags')) {
event(new FlagsUpdated($model));
}
});
}
}
How can I help you explore Laravel packages today?