★ The mixin PHP DocBlock
Tags: php
Published: 2020-01-02 23:39:42

---
title: ★ The mixin PHP DocBlock
published: true
date: 2019-10-14 11:11:56 UTC
tags: php
canonical_url: https://freek.dev/1482-the-mixin-php-docblock
---

When using PHP, you've probably used [DocBlocks](https://en.wikipedia.org/wiki/PHPDoc). They can be used to add additional information that can't be inferred by looking at the source code alone. DocBlocks can be used by IDEs, like PhpStorm, to improve autocomplete suggestions.

In this blogpost, I'd like to highlight a not so well known DocBlock: mixin.

## A first example of a DocBlock #

Before looking at a mixin DocBlock, let's first get a feel of how DocBlocks can make autocompletion better.

```php
/**
 * @return \App\Models\Post[]
 */
public function allPosts(): array
{
    // ...
}
```

With regular type hints, you can only specify that the function returns an array. The DocBlock to signals that the function returns an array of `\App\Models\Post` objects.

When you loop through the value returned by `allPosts` an IDE knows which kind of object is inside the array and can provide autocompletion for that object.

## A theoretical first example #

The mixin DocBlock allows you to signal that all properties and methods of another class are available on the class where the mixin is applied upon.

Here's some contrived code to illustrate it:

```php
class ClassA
{
    public function methodOfClassA(): string
    {
        return 'This is classA';
    }
}

/** @mixin ClassA */
class ClassB
{
    public function methodOfClassB(): string
    {
        return 'This is classB';
    }

    public function __call($name, $arguments)
    {
        (new ClassA())->$name(...$arguments);
    }
}
```

If you call a method a method on `classB` that isn't available, it will defer to calling `classA`. The intention here is to make every method that is available on `classA` part of `classB` as well.

Thanks to that `mixin` DocBlock, an IDE knows that intention as well and will also suggest functions of `classA` when calling methods on `classB`

![Screenshot](https://freek.dev/uploads/media/mixin-docblock/1.png)

## A practical example #

Let's take a look at some practical example of how this can be used.

[laravel-medialibrary](https://docs.spatie.be/laravel-medialibrary/v7/introduction/) is a package that can be used to associate Eloquent models with media. One of its features is the ability to [generate conversions](https://docs.spatie.be/laravel-medialibrary/v7/converting-images/defining-conversions/) whenever an image is being associated with a model.

A conversion can be defined on a model like this.

```php
public function registerMediaConversions(Media $media = null)
{
    $this->addMediaConversion('thumb')
          ->width(368)
          ->height(232)
          ->sharpen(10);
}
```

So you first call `addMediaConversion` and then you can call any manipulations, like `width` and `height`, you want.

Behind the scenes, the `addMediaConversion` will return an instance of [`Spatie\MediaLibrary\Conversion\Conversion`](https://github.com/spatie/laravel-medialibrary/blob/089ee0784b9b539331048a5fa144d050e30711c1/src/Conversion/Conversion.php). This class is responsible for handling the registration of the image conversions. It does not directly handle image manipulations like `width` or `height`. Those are handled by `Spatie\Image\Manipulations`. Whenever we call a function on `Conversion` that doesn't exist on itself, it will defer the call to `Manipulations`. The deferring is done by [this piece of code](https://github.com/spatie/laravel-medialibrary/blob/089ee0784b9b539331048a5fa144d050e30711c1/src/Conversion/Conversion.php#L98-L107).

```php
public function __call($name, $arguments)
{
    if (! method_exists($this->manipulations, $name)) {
        throw new BadMethodCallException("Manipulation `{$name}` does not exist");
    }

    $this->manipulations->$name(...$arguments);

    return $this;
}
```

With this code in place, it will all work, but the developer experience won't be great. The IDE will offer no autocompletion when typing `$this->addMediaConversion('thumb')->`. To make autocompletion work we added [this mixin](https://github.com/spatie/laravel-medialibrary/blob/089ee0784b9b539331048a5fa144d050e30711c1/src/Conversion/Conversion.php#L8) at the top of the `Conversion` class.

```php
/** @mixin \Spatie\Image\Manipulations */
```

That mixin allows the IDE to add autocompletion, so developers can just pick the image manipulation method they want.

![Screenshot](https://freek.dev/uploads/media/mixin-docblock/2.png)

## Using a mixin DocBlock to autocomplete Laravel API resources #

In the previous example the `mixin` DocBlock was used within package code, but you can use it inside projects too. At [Spatie](https://spatie.be), they are often using in Laravel's [API resources](https://laravel.com/docs/master/eloquent-resources).

An API resource is a class that maps the attributes of an model to the properties on an API response. Here's an example of such a resource.

```php
namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email,
            'avatar_url' => $this->getFirstMediaUrl('avatar'),
        ];
    }
}
```

In an API resource in Laravel, calling a property on `$this` will get the property of the underlying model. But as it stands, typing `$this->` will not offer autocompletion of the model attributes.

We must perform two steps to get autocompletions. First, we must let our IDE know which attributes there are on the model. We can use the excellent [barryvdh/laravel-ide-helper](https://github.com/barryvdh/laravel-ide-helper) for this. With the package installed, executing `php artisan ide-helper:models` will generate a file that lets your IDE know which properties there are available on a model.

The second and final step to get autocompletion working on API resource is adding a mixin DocBlock on it.

```php
/** @mixin \App\User */
class UserResource extends JsonResource
```

With this in place, autocompletion will work.

![Screenshot](https://freek.dev/uploads/media/mixin-docblock/3.png)

## Closing thoughts #

A mixin DocBlock can be used to hint that methods from another class are available on the class where the DocBlock is applied on.

There is no formal standard of which DocBlocks are available. The de facto standard is this list on the documentation of [phpDocumentor](https://docs.phpdoc.org/guides/docblocks.html#list-of-tags). You'll notice that the mixin DocBlock isn't there. So be aware that this DocBlock probably doesn't work in any IDE. In PhpStorm, it works perfectly.