ArrayAccess on a value object is usually a mistake

Implementing ArrayAccess so a class can be used with square brackets makes it look like an array to every reader and to no static analyser.

$config['database']['host'];     // is this an array? a class? both?

// what the analyser sees with ArrayAccess:
//   offsetGet(mixed $offset): mixed
// which is: anything in, anything out. no checking at all.

// what a named method gives it:
$config->database()->host();    // string, checked, autocompleted

The interface predates return types and cannot express what a given offset returns, so every access is mixed and the tooling has nothing to work with. It also cannot be type-hinted against usefully — a function accepting ArrayAccess knows nothing about what is in it. The legitimate uses are containers that genuinely are collections with arbitrary keys, and even then ArrayAccess plus Countable plus IteratorAggregate is three interfaces where one named class would have been clearer.