henrywhitaker3/bitmasked-properties

一个用于在类中使用位掩码属性的包

v1.0.0 2021-11-23 02:20 UTC

This package is auto-updated.

Last update: 2024-09-08 17:57:52 UTC


README

这个库提供了一个特性,用于在PHP 8.1枚举中使用位掩码属性。我正在阅读这篇文章,并且能想到一些地方可以使用这个功能,所以我决定制作这个库,使其更加可重用;这也是开始尝试使用PHP 8.1枚举的一个好方法。

安装

composer require henrywhitaker3/bitmasked-properties

使用方法

例如,你有一个名为 Person 的模型,可以选择或取消选择邮件和短信通信。一个简单(并不好)的方法是在数据库中为每个方法创建单独的列来存储这些信息

class Person
{
    public function __construct(
        public bool $sms,
        public bool $email
    ) {}

    public function isOptedIn(string $type): bool
    {
        // Should really check the value of type is valid first...
        return $this->{$type};
    }

    public function optin(string $type): void
    {
        $this->updateOptin($type, true);
    }

    public function optout(string $type): void
    {
        $this->updateOptin($type, false);
    }

    private function updateOptin(string $type, bool $value): void
    {
        switch($type) {
            case 'sms':
                $this->sms = $value;
                break;
            case 'email':
                $this->email = $value;
                break;
        }
    }
}

这需要硬编码字段名,并且每次出现新的通信类型时,都需要运行迁移来添加列,这有点令人反感。

在某些情况下,使用位掩码字段将是一个更好的解决方案——尽管你不能对这些值进行索引,因此无法非常有效地查询它们。但是,它允许你在添加新的通信类型时无需更改数据库或代码即可添加新的枚举情况。使用这个方法,你可以在标准整数字段中拥有多达32个不同的布尔值。以下是如何在上述示例中使用它的方法

enum Optin: int implements BitmaskEnum
{
    case SMS = 1 << 0; // 1
    case EMAIL = 1 << 1; // 2
}
class Person
{
    use HasBitmaskedProperties;

    public function __construct(
        public bool $optin
    ) {}

    public function isOptedIn(Optin $type): bool
    {
        return $this->getFlag('optin', $type);
    }

    public function optin(Optin $type): void
    {
        $this->setFlag('optin', $type, true);
    }

    public function optout(Optin $type): void
    {
        $this->setFlag('optin', $type, false);
    }

    public function getOptins(): WeakMap
    {
        return $this->flagToWeakmap('optin', Optin::class);
    }
}

现在使用它非常简单

$person = new Person; // $optin === 0

$person->isOptedIn(Optin::SMS); // returns false
$person->optin(Optin::SMS); // $optin === 1
$person->isOptedIn(Optin::SMS); // returns true

$person->optin(Optin::EMAIL); // $optin === 3
$person->isOptedIn(Optin::EMAIL); // returns true

$person->optout(Optin::SMS); // $optin === 2
$person->isOptedIn(Optin::SMS); // returns false

$person->getOptins()[Optin::EMAIL]; // return true

你可以在不更改数据库或代码的情况下向 Optin 枚举中添加新值。