Attributes in Laravel Under the Hood.

Oleksandr Bredikhin
5 min readJan 25, 2025

--

Attributes in PHP, introduced in version 8.0, provide a way to add metadata to classes, methods, properties, and more. In Laravel, attributes can be leveraged to simplify dependency injection and make your code more expressive.

1. Implementation under the hood.

In Laravel, attributes intended for contextual dependency resolution must implement the ContextualAttribute interface. This ensures that Laravel's service container can properly resolve these attributes when applied to parameters. While ContextualAttribute is an empty interface, you must implement resolve method, to handle the dependency logic.

Inside the framework, it checks if the attribute implements ContextualAttribute and then calls the resolveFromAttribute method.

You can also register a callback for a specific attribute using the whenHasAttribute method. This method allows you to register a function that will be executed when an attribute with a specific class is found during the dependency resolution process.

Another method you can use is called after, which is executed after resolving. The after method in attributes allows for specific actions or data processing to be performed after an object is created. Here are some examples:

Data Processing
Attributes can contain logic that should be executed after an object is initialized or certain steps are completed. For instance, you can configure relationships between objects or process data that was set in the object.

Post-Processing Hooks
The after method can act as a hook, allowing additional functionality to be executed after the main process. For example, it can handle logging.

Context Integration
Attributes can include context-dependent logic, and the after method enables this logic to interact with the object or the system.

The after method accepts three parameters. The first is the attribute itself, the second is the object that was created in the resolve method, and the third is the container.

Also under the hood, Laravel also checks if any callbacks are registered for the given attribute, and if so, it executes them.

Callbacks are useful when you want to perform actions with already existing attributes, such as attributes from a package or those provided by Laravel itself. More on this will be discussed below. To do this, you need to call the afterResolvingAttribute method on the container and pass the callback. The parameters of this method are the same as those in the after method.

2) Let’s look at an example of why attributes can be useful for you.

We will create a custom attribute called Autowired, which will enable automatic dependency injection based on the specified class.

Here’s what’s happening in the Autowired attribute:

  1. Attribute Declaration: #[Attribute(Attribute::TARGET_PARAMETER)] specifies that this attribute can only be applied to parameters.
  2. Dependency Resolution: The resolve method uses Laravel's container to resolve the class passed to the attribute.
  3. Constructor: Accepts the class name of the dependency to inject.

Defining the Repository

The repository pattern separates the data access logic from the service layer. Here’s the interface and implementation:

Next, let’s use the Autowired attribute to inject a repository into a service.

By creating a custom Autowired attribute, you can streamline dependency injection and make your Laravel applications more expressive and maintainable. Instead of manually specifying bindings for repositories in a service provider, you can use the #[Autowired] attribute to automatically inject the correct implementation or configuration directly where it's needed. This eliminates the need for repetitive $this->app->when() statements for specific business logic.

3. What attributes already exist.

#[Auth]

The #[Auth] attribute allows for seamless integration with Laravel's authentication system and simplifies access to the authentication guard.

#[Cache]

The #[Cache] attribute makes it easier to work with Laravel's caching mechanism by automatically resolving cache store instances.

#[Config]

The #[Config] attribute simplifies access to Laravel's configuration values by injecting them directly where needed.

#[CurrentUser]

The #[CurrentUser] attribute allows you to retrieve the currently authenticated user in a concise and elegant way.

#[DB]

Injects a specific database connection.

#[Log]

The #[Log] attribute provides access to logger instance.

#[RouteParameter]

The #[RouteParameter] attribute automatically resolves route parameters, making it easier to handle dynamic routes.

#[Storage]

The #[Storage] attribute allows you to work with Laravel's storage system.

#[Tag]

Tags a service for later retrieval.

As conclusion.

Laravel attributes provide a powerful way to enhance and simplify dependency injection, configuration handling, and other core functionalities within your application.

I’d love to hear your thoughts! Share in the comments which attributes you would like to use or see implemented. Additionally, feel free to share your ideas on how you plan to use methods like after and afterResolvingAttribute. Your input might inspire new and exciting use cases!

--

--

Oleksandr Bredikhin
Oleksandr Bredikhin

Written by Oleksandr Bredikhin

Software Engineer PHP | Java | JS | AWS

No responses yet