Можно через наследование 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 не умеет перегружать методы с разными наборами параметров.