Alternatives to using a constants.php file in your Laravel project
Tags: php, laravel, constants
Published: 2021-07-22 12:54:55

One of the common patterns I have come across in Laravel projects is the use of a `constants.php` file carrying a long list of all constants used across the application. 

While there may be good use cases for having such a file, I'm writing this article to suggest a few alternative approaches. My intent is not to advertise these as "best practices", but leave it for you to decide what fits best your specific situation. 

Let's assume that our original `constants.php` file looks like this: 
```php
const ADMIN_ROLE = 1;
const EDITOR_ROLE = 2;
const PUBLISHER_ROLE = 3;
```

## Configuration files
As pointed out by the most upvoted answer in [this popular thread](https://stackoverflow.com/questions/42155536/what-is-the-best-practice-for-adding-constants-in-laravel-long-list), one way to manage constant values in your Laravel app is to park them as configurations.

My only variation to this approach is to use a more specific file name depending on the *context*, which in this case could be `roles.php`:

```php
<?php

return [
  'admin' => 1,
  'editor' => 2,
  'publisher' => 3
];
```

This would allow me to access those values throughout my application using: 

```php
config('roles.admin'); // Using helper functions

Config::get('roles.admin'); // Using facades
```

The benefit of this approach compared to using a plain `constants.php` file is that it uses the framework's original mechanics to store and access values. Laravel configurations are familiar to most developers,  and so people new to your code won't have to learn something new to use them.

The downside is that, unless you use a plugin such as [Laravel Idea](https://laravel-idea.com/), most IDEs won't autocomplete config keys for you.

## Constants in your classes
Another approach, which is more inline with OOP, is to keep your constants in the specific *context* (i.e. classes) they belong. 

In the case of user role constants, for example, we could keep everything under the `User` model class: 

```php
class User extends Model {
  const ADMIN_ROLE = 1;
  const EDITOR_ROLE = 2;
  const PUBLISHER_ROLE = 3;
  
  public function isAdmin(){
    return $this->role === static::ADMIN_ROLE;
  }
}
```

To take this one step further, you may consider creating a dedicated `Role` class that contains all values/logic related  to roles:

```php
class Role {
  const ADMIN = 1;
  const EDITOR = 2;
  const PUBLISHER = 3;
}
```

This would enable a more expressive syntax when you're trying to access your constants:

```php
class User extends Model {  
  public function isAdmin(){
    return $this->role === Role::ADMIN;
  }
}
```


## Enum values
Another alternative to constants that are related to a specific model is to use enumerated (ENUM) types at your database level. 


When using your migration for your `users` table, you may use the `enum` function to create your column: 
```php
public function up()
{
  Schema::create('users', function (Blueprint $table) 
  {
    $table->enum('role', ['admin', 'editor', 'publisher']);
    // Other columns...
  });
}
```

While ENUMs are compact values (e.g. in MySQL they are automatically encoded as numbers behind the scenes), they allow you to deal with readable string values in your application:

```php
class User extends Model {
  public function isAdmin(){
    return $this->role === 'admin';
  }
}
```

If you are going for this approach, you should note that not every database engine supports ENUMs (e.g. MySQL and PostgreSQL both support ENUMs, but SQLite doesn't).


## What do you think?
What are some other values you store in a `constants.php` file? Where else do you place your constants?