Skip to content

Instantly share code, notes, and snippets.

@themsaid
Last active August 29, 2020 23:23
Show Gist options
  • Save themsaid/593a1972adbe35150e730c0ad3632cad to your computer and use it in GitHub Desktop.
Save themsaid/593a1972adbe35150e730c0ad3632cad to your computer and use it in GitHub Desktop.
PHP Enumerated Type
trait HasEnums
{
/**
* The array of enumerators of a given group.
*
* @param null|string $group
* @return array
*/
static function enums($group = null)
{
$constants = (new ReflectionClass(get_called_class()))->getConstants();
if ($group) {
return array_filter($constants, function ($key) use ($group) {
return strpos($key, $group.'_') === 0;
}, ARRAY_FILTER_USE_KEY);
}
return $constants;
}
/**
* Check if the given value is valid within the given group.
*
* @param mixed $value
* @param null|string $group
* @return bool
*/
static function isValidEnumValue($value, $group = null)
{
$constants = static::enums($group);
return in_array($value, $constants);
}
/**
* Check if the given key exists.
*
* @param mixed $key
* @return bool
*/
static function isValidEnumKey($key)
{
return array_key_exists($key, static::enums());
}
}
@crossRT
Copy link

crossRT commented Apr 28, 2016

Nice! Thanks for sharing.

@fer-ri
Copy link

fer-ri commented Apr 29, 2016

Its really great! 👍

@joelcuevas
Copy link

I came up with something almost identical a time ago!

I also use a method called const (never thought of a better name) in the trait that checks if an object's auto-detected attribute is equal to a constant in the model.

public function const($constant)
{
    $constants = (new ReflectionClass(get_called_class()))->getConstants();

    if (isset($constants[$constant])) {
        $attr = strtolower(explode('_', $constant)[0]);

        return $this->$attr == $constants[$constant];
    }

    return false;
}

So I can do something like:

$order->const('TYPE_DINE_IN');

Which is equivalent to:

$order->type == App\Models\Order::TYPE_DINE_IN;

Yes, I like to put all my models in its own namespace, and with this, I can avoid namespacing the constants in, for example, Blade views:

// normally
@if ($order->type == App\Models\Order::TYPE_TAKEAWAY)
    // some code
@endif

// with trait
@if ($order->const('TYPE_TAKEAWAY'))
    // some code
@endif

Of course, this method has some shortcomings —like if your attribute has a composite name like $order->delivery_status and your constants are in the form of DELIVERY_STATUS_SENT— because the method expects a single word in the attribute name, but it works for me the 99% of the time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment