OOP:  Трейты (trait)
Glossary overview

OOP:  Трейты (trait)

Trait (трейт) в PHP — это механизм повторного использования кода, предназначенный для преодоления ограничений одиночного наследования. Он позволяет включать наборы методов в несколько независимых классов, обеспечивая «горизонтальную» композицию поведения, без необходимости создания сложной иерархии наследования.

Пример использования в плагине

Проблема

В плагине есть два абсолютно разных класса:

abstract class Options { ... }   // Страница настроек в админке
abstract class Metabox { ... }   // Поля в редакторе поста

Они про разные вещи. Наследовать друг от друга — бессмысленно. Но обоим нужна одна и та же логика: работа с секциями и полями.

Оба хранят массив секций. Оба умеют получить все поля, найти поле по имени, добавить секцию. Копировать этот код в два класса — дублирование.

Решение: trait HasSections

trait HasSections
{
    protected array $sections = [];

    public function sections(): array
    {
        return $this->sections;
    }

    public function allFields(): array
    {
        return array_merge(...array_column($this->sections(), 'fields'));
    }

    public function fieldByName(string $name): ?Field
    {
        foreach ($this->allFields() as $field) {
            if ($field->name === $name) {
                return $field;
            }
        }
        return null;
    }

    public function defaultValue(string $name): mixed { ... }

    protected function appendSection(array $section): void { ... }
}

Как подключается — одна строка use

abstract class Options
{
    use HasSections;   // ← Options получил sections(), allFields(), fieldByName()...
    // свои свойства и методы
}

abstract class Metabox
{
    use HasSections;   // ← Metabox получил те же самые методы
    // свои свойства и методы
}

use HasSections — PHP буквально вставляет код трейта внутрь класса. Как если бы ты скопировал все методы руками, но без дублирования.

Как это используется дальше

// PluginOptions.php (наследник Options)
protected function __construct()
{
    $all_options = array_map(fn($path) => include $path, $options_files);

    $this->setSections($all_options);
    //     ↑ метод из HasSections, доступен через Options
}

// PostMeta.php (наследник Metabox)
public function __construct(array $sections)
{
    array_walk($sections, [$this, 'appendSection']);
    //                              ↑ метод из HasSections, доступен через Metabox
}

Оба вызывают appendSection() — но ни Options, ни Metabox этот метод не определяют. Он приходит из трейта.