Задать вопрос

Определение значений передаваемой в функцию переменной типа массив?

Можно ли каким то образом, через интерфейс или абстракцию (встроенными средствами) объявить ключи принимаемой в функции переменной типа массив?

interface Parameters
{

    public $array = [
        "key_1" => "value_1",
        "key_2" => "value_3",
        "key_3" => "value_3",        
    ]
}

class Main implements Parameters
{

    public function execute(Parameters $array): string ¯\_(ツ)_/¯
    {
        
    }
}
  • Вопрос задан
  • 357 просмотров
Подписаться 2 Простой 1 комментарий
Решения вопроса 1
ipatiev
@ipatiev Куратор тега PHP
Потомок старинного рода Ипатьевых-Колотитьевых
Это один из тех вопросов новичков, на который нельзя давать прямой ответ. Он превратится в пустое умствование и говнокод. Соглашусь с комментарием Дмитрий: тут просто не нужен массив. И тем более не нужно городить огород из абстракций. Тут явно нужен банальный VO/DTO, а автору надо перестать пытаться заворачивать привычные массивы в солидно выглядящие объекты, и начать использовать сами объекты.

Если нам нужна конкретная структура, то и описываем её в конкретном классе, безо всяких интерфейсов:

final readonly class Parameters
{
    public function __construct(
        public string $key1,
        public int $key2,
        public DateTimeImmutable $key3,
    ) {}
}
public function execute(Parameters $parameters):


В итоге у "стороннего разработчика" есть готовая документация - простое и понятное определение класса, экземпляр которого он должен передать в ваш метод. И уже на этапе создания этого объекта РНР надаёт разработчику по рукам, если хоть какое-то свойство не будет задано, или будет не того типа. При желании можно в конструктор добавить дополнительную валидацию, если просто типа недостаточно.

При этом если внутри execute() вдруг зачем-то понадобится обратиться к свойствам именно как к массиву, то использовать волшебную функцию get_object_vars().

Если же речь про валидацию входящих данных, то это вообще совсем другой вопрос.

Для этого есть либо стандартные валидаторы, когда на вход подаётся массив и набор правил, вот например как в ларавле, симфони или в десятке отдельно стоящих библиотек, а на выходе - или гарантированно валидная структура данных, или ошибка.

Либо готовые библиотеки десериализации, когда входящий JSON автоматом мапится на существующий объект, и в итоге получается или либо гарантированно валидный объект, или ошибка.

В этом случае документацией для обоих вариантов является сваггер, а фидбеком - ошибки валидатора.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
Можно через наследование ArrayObject, при этом сохранится доступ как к массиву и можно итерировать по объекту. Однократный перебор ключей массива всё равно понадобится, чтобы оставить только строковые ключи.
declare(strict_types=1);

abstract class StrictArray extends ArrayObject
{
    final public function __construct(array $array = []) {
        $this->checkArray(
            ...array_filter(
                $array,
                static fn(int|string $key): bool => is_string($key),
                ARRAY_FILTER_USE_KEY,
            ),
        );
        parent::__construct(array: $array);
    }

    #[Override]
    public function append(mixed $value): void
    {
        // Заглушка для запрета добавления значения в массив
    }

    #[Override]
    public function offsetSet(mixed $key, mixed $value): void
    {
        // Заглушка для запрета установки значения по ключу
    }
}

final class Parameters extends StrictArray
{
    protected function checkArray(
        int $keyInt,
        string $keyString,
        bool $keyBool = false,
        ?DateTimeImmutable $keyDate= null,
    ): void {
    }
}

$parameters = new Parameters([
    'keyInt' => 1,
    'keyDate' => new DateTimeImmutable('now'),
    'keyBool' => true,
    'keyString' => 'abc'
]);

Не очень красиво, что в StrictArray не определяется сигнатура для checkArray, но PHP не умеет перегружать методы с разными наборами параметров.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы