What is the Purpose of the `backed` Type in Enums?
PHP

What is the Purpose of the `backed` Type in Enums?

Symfony Certification Exam

Expert Author

January 29, 20266 min read
PHP EnumsSymfonySymfony CertificationEnums in PHP

What is the Purpose of the backed Type in Enums?

PHP 8.1 introduced enums, providing a new way to define a set of possible values for a variable. Among the types of enums, the backed type serves a specific purpose that is especially beneficial for Symfony developers. Understanding the backed type in enums is crucial not only for mastering modern PHP but also for excelling in Symfony applications and preparing for the Symfony certification exam.

In this article, we will explore the purpose of the backed type in enums, how it works, and practical examples that illustrate its use in Symfony applications. By the end of this post, you will have a clearer understanding of how to implement and leverage backed enums in your Symfony projects.

What are Enums?

Before diving into the backed type, let’s briefly recap what enums are and why they are important. Enums allow developers to define a set of named constants, providing a clear and type-safe way to represent a fixed set of values. In PHP, there are two types of enums:

  • Pure Enums: These enums do not have associated values and are simply a collection of named constants.
  • Backed Enums: These enums have a specific underlying type (either string or int) and can be used to associate values with their names.

Why Use Backed Enums?

The backed type is particularly useful in scenarios where you want to represent a set of values that have a corresponding scalar value. This can include cases like status codes, types of user roles, or any other fixed set of values where the underlying representation is essential.

Defining a Backed Enum in PHP

To define a backed enum, you use the enum keyword followed by the name of the enum and the backed type declaration. Here’s an example of a simple backed enum representing user roles:

enum UserRole: string
{
    case ADMIN = 'admin';
    case EDITOR = 'editor';
    case VIEWER = 'viewer';
}

In this example, the UserRole enum has three cases, each associated with a string value. This structure allows you to enforce type safety and provides a clear representation of user roles.

Practical Use Cases of Backed Enums in Symfony Applications

Understanding the backed type in enums is vital for Symfony developers as it has several practical applications in everyday coding scenarios.

1. Implementing User Roles with Backed Enums

In a Symfony application, user roles are a common use case. Using a backed enum can enhance the clarity and maintainability of your code.

Here’s how you might use the UserRole enum within a Symfony entity:

use DoctrineORMMapping as ORM;

#[ORMEntity]
class User
{
    #[ORMId]
    #[ORMGeneratedValue]
    private int $id;

    private string $username;

    private UserRole $role;

    public function __construct(string $username, UserRole $role)
    {
        $this->username = $username;
        $this->role = $role;
    }

    public function getRole(): UserRole
    {
        return $this->role;
    }

    public function isAdmin(): bool
    {
        return $this->role === UserRole::ADMIN;
    }
}

In this example, the User entity uses the UserRole enum to enforce valid user roles. This approach not only improves type safety but also makes it easier to manage permissions based on user roles.

2. Handling Status Codes with Backed Enums

Another practical application is managing status codes, such as for order processing in an e-commerce application. You can define a backed enum for order statuses:

enum OrderStatus: string
{
    case PENDING = 'pending';
    case PROCESSING = 'processing';
    case COMPLETED = 'completed';
    case CANCELLED = 'cancelled';
}

You can then use this enum in your order entity:

#[ORMEntity]
class Order
{
    #[ORMId]
    #[ORMGeneratedValue]
    private int $id;

    private OrderStatus $status;

    public function __construct(OrderStatus $status)
    {
        $this->status = $status;
    }

    public function getStatus(): OrderStatus
    {
        return $this->status;
    }

    public function cancelOrder(): void
    {
        if ($this->status === OrderStatus::PENDING) {
            $this->status = OrderStatus::CANCELLED;
        }
    }
}

By using a backed enum for order statuses, you ensure that only valid statuses are assigned to an order, thus preventing invalid states and improving code robustness.

3. Working with Doctrine DQL Queries

Backed enums also simplify the process of working with Doctrine DQL queries. When constructing queries, you can use the enum values directly, ensuring consistency and reducing the risk of errors.

For example, if you want to retrieve all completed orders, you can write a query like this:

$query = $entityManager->createQuery(
    'SELECT o FROM App\Entity\Order o WHERE o.status = :status'
)->setParameter('status', OrderStatus::COMPLETED->value);

$completedOrders = $query->getResult();

4. Using Backed Enums in Symfony Forms

Another area where backed enums shine is in Symfony forms. You can leverage enums to create form fields that correspond to enum cases, ensuring that only valid values are submitted.

Here’s how you can integrate a backed enum into a Symfony form:

use SymfonyComponent\FormAbstractType;
use SymfonyComponent\FormFormBuilderInterface;
use SymfonyComponent\OptionsResolverOptionsResolver;

class UserType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('username')
            ->add('role', ChoiceType::class, [
                'choices' => [
                    'Admin' => UserRole::ADMIN->value,
                    'Editor' => UserRole::EDITOR->value,
                    'Viewer' => UserRole::VIEWER->value,
                ],
            ]);
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => User::class,
        ]);
    }
}

In this form type, we define a role field that uses the UserRole enum for its choices. This ensures that only valid roles can be selected when creating or updating a user.

Advantages of Using Backed Enums

1. Type Safety

One of the primary advantages of using backed enums is type safety. By using enums, you prevent invalid values from being assigned to your variables, reducing the risk of runtime errors.

2. Improved Readability

Enums enhance code readability by providing meaningful names for constants. This makes it easier for developers to understand the purpose of each value without needing to refer to documentation or comments.

3. Easy Refactoring

When you use enums, changing a value or adding a new case is straightforward. You only need to update the enum definition, and the changes will propagate throughout your codebase, minimizing the risk of errors.

4. Integration with Symfony Features

Backed enums integrate seamlessly with Symfony features like forms and validation, allowing you to leverage their benefits across the framework.

Conclusion

The backed type in enums is a powerful feature that enhances the way Symfony developers manage fixed sets of values. By providing type safety, improved readability, and seamless integration with Symfony components, backed enums simplify code management and reduce errors.

As you prepare for the Symfony certification exam, understanding the purpose and practical applications of the backed type in enums will be invaluable. Whether you’re working with user roles, order statuses, or other fixed sets of values, leveraging backed enums will help you write cleaner, more maintainable code.

Incorporate this knowledge into your Symfony projects, and you'll not only enhance your coding skills but also position yourself for success in your certification journey. Embrace the power of backed enums, and take your Symfony applications to the next level!