Перейти к основному содержимому

Примеры использования и лучшие практики

Лучшие практики

1. Использование конструктора с продвижением свойств

Лучшей практикой является использование конструктора для объявления публичных свойств через продвижение. Это упрощает создание объекта и делает код более чистым и понятным.

Когда мы объявляем свойства в корне класса и полагаемся только на метод from(), мы теряем гибкость и прямой контроль над созданием объекта. Такое решение может выглядеть привлекательным из-за простоты, но оно ограничивает нас в возможности напрямую работать с объектом через конструктор.

Пример плохой практики:

class User extends Data {
public string $name;
public int $age;
}

$data = [
'name' => 'John Doe',
'age' => '30'
];

// Создание объекта через from
$user = User::from($data);

Здесь мы теряем возможность явно контролировать создание объекта через конструктор, что может привести к путанице, если понадобятся дополнительные действия при создании объекта, такие как валидация или преобразование данных.

Пример хорошей практики:

class User extends Data {
public function __construct(
public string $name,
public int $age
) {}
}

$data = [
'name' => 'John Doe',
'age' => 30
];

// Создание объекта с использованием конструктора
$user = new User(name: $data['name'], age: $data['age']);

Здесь мы сохраняем прямой контроль над процессом создания объекта и можем легко управлять поведением объекта при его создании.

2. Совмещение атрибутов для одного поля

Можно комбинировать несколько атрибутов для одного поля. Это даёт мощные возможности для преобразования данных, особенно в случаях, когда нужно проводить несколько этапов обработки.

Пример: если нам нужно парсить поле user из user_id и использовать парсер, который по этому ID находит объект пользователя, мы можем применить атрибуты ParseFrom и ParseBy вместе.

Пример:

use Looqey\Speca\Data;
use Looqey\Speca\Attributes\ParseBy;
use Looqey\Speca\Attributes\ParseFrom;
use Looqey\Speca\Contracts\Transformer;

class User extends Data {
public function __construct(
#[ParseBy(UserIdToUserParser::class)]
#[ParseFrom('user_id')]
public User $user
) {}
}

class UserIdToUserParser implements Transformer {
public function transformer(mixed $value, Property $property): mixed {
// Ищем пользователя по ID
return User::findById($value);
}
}

$data = [
'user_id' => '12345'
];

$user = User::from($data);

Здесь сначала атрибут ParseFrom указывает, что данные для поля user приходят из поля user_id, а атрибут ParseBy использует парсер, который находит пользователя по этому ID. Это позволяет комбинировать правила парсинга и при этом сохранять логику гибкой и масштабируемой.

3. Использование кэширования для повторяющихся запросов

Если атрибуты или парсеры могут повторно использовать данные (например, пользователь с одинаковым user_id), стоит рассмотреть внедрение кэширования для таких данных на уровне входных данных. Например, можно использовать хранилище уровня запроса для того, чтобы один раз загрузить объект пользователя по ID и вернуть его при следующем запросе, значительно ускоряя обработку.

Пример:

use Looqey\Speca\Data;
use Looqey\Speca\Attributes\ParseBy;
use Looqey\Speca\Attributes\ParseFrom;
use Looqey\Speca\Contracts\Transformer;

class User extends Data {
public function __construct(
#[ParseBy(UserIdToUserParser::class)]
#[ParseFrom('user_id')]
public User $user
) {}
}

class UserIdToUserParser implements Transformer {
public function transform(mixed $value, Property $property): mixed {
// Ищем пользователя по ID
return User::findById($value);
}
}

$data = [
'user_id' => '12345'
];

$user = User::from($data);

Здесь сначала атрибут ParseFrom указывает, что данные для поля user приходят из поля user_id, а атрибут ParseBy использует парсер, который находит пользователя по этому ID. Это позволяет комбинировать правила парсинга и при этом сохранять логику гибкой и масштабируемой.

3. Использование кэширования для повторяющихся запросов

Если атрибуты или парсеры могут повторно использовать данные (например, пользователь с одинаковым user_id), стоит рассмотреть внедрение кэширования для таких данных на уровне входных данных. Например, можно использовать хранилище уровня запроса для того, чтобы один раз загрузить объект пользователя по ID и вернуть его при следующем запросе (при конструировании другого Data-объекта), значительно ускоряя обработку.

Пример:

class UserIdToUserParser implements Transformer {
private static array $cache = [];

public function transform(mixed $value, Property $property): mixed {
// Если объект уже в кэше, возвращаем его
if (isset(self::$cache[$value])) {
return self::$cache[$value];
}

// Если объекта нет в кэше, загружаем его и сохраняем в кэш
$user = User::findById($value);
self::$cache[$value] = $user;
return $user;
}
}

Этот подход будет эффективен при работе с данными, которые часто повторяются, и поможет избежать лишних запросов или операций.

4. Управление включениями и исключениями

Когда речь идет о "тяжелых" или ленивых данных, важно эффективно управлять включениями и исключениями полей в сериализации. Использование методов include и exclude помогает контролировать, какие данные включать в вывод, что позволяет экономить ресурсы.

Пример:

$user = new User('John Doe', 30);
$user->include('profile'); // Включаем профиль в вывод
$user->exclude('password'); // Исключаем пароль из вывода

$data = $user->toArray();

Этот метод позволяет вам исключать или включать данные по мере необходимости, что идеально подходит для работы с большими или чувствительными данными.