Extract ArrayAccessRead from ArrayAccess

php.internals

Удальцов Валентин

2 years ago
Hello, internals! Recently I was implementing some collections and realized that I cannot use `ArrayAccess` for immutable collections without throwing `BadMethodCallException` in `offsetSet` and `offsetUnset`. I also cannot have an `interface ReadonlyCollection extends ArrayAccess`, because `offsetSet` and `offsetUnset` are mutators and have `TValue` in a contravariant position. Here's the idea: let's extract `ArrayAccess::offsetExists` and `ArrayAccess::offsetGet` methods into a separate `ArrayAccessRead` interface (name can be different) and allow read operations `$exists = isset($object['key'])` and `$value = $object['key']` for objects of classes that implement this interface. `ArrayAccess` will then extend `ArrayAccessRead` and add the remaining 2 methods. Looks like this change should not break backward compatibility. ``` interface ArrayAccessRead { public function offsetExists(mixed $offset): bool; public function offsetGet(mixed $offset): mixed; } interface ArrayAccess extends ArrayAccessRead { public function offsetSet(mixed $offset, mixed $value): void; public function offsetUnset(mixed $offset): void; } // then interfaces of the doctrine/collections package might look like this: namespace Doctrine\Common\Collections; interface ReadableCollection extends Countable, IteratorAggregate, ArrayAccessRead {} interface Collection extends ReadableCollection, ArrayAccess {} ```
-- Regards, Valentin Udaltsov

Alexandru Pătrănescu

2 years ago
On Mon, May 27, 2024 at 7:16 AM Valentin Udaltsov < udaltsov.valentin@gmail.com> wrote:
> Hello, internals! > > Here's the idea: let's extract `ArrayAccess::offsetExists` and > `ArrayAccess::offsetGet` methods into a separate `ArrayAccessRead` > interface (name can be different) and allow read operations `$exists = > isset($object['key'])` and `$value = $object['key']` for objects of classes > that implement this interface. `ArrayAccess` will then extend > `ArrayAccessRead` and add the remaining 2 methods. Looks like this change > should not break backward compatibility. > >
Please check this: https://externals.io/message/122609#122609 where Gina analyzed and proposed a solution for this. It looks like the DimensionReadable is exactly the same thing. Maybe also DimensionFetchable if you consider returning by reference. Maybe the improvement can be done in smaller incremental steps, but I think it's better to agree on a complete solution for splitting ArrayAccess. Regards, Alex

Удальцов Валентин

2 years ago
On Mon, May 27, 2024 at 14:21 Alexandru Pătrănescu <drealecs@gmail.com> wrote:
> > On Mon, May 27, 2024 at 7:16 AM Valentin Udaltsov < > udaltsov.valentin@gmail.com> wrote: > >> Hello, internals! >> >> Here's the idea: let's extract `ArrayAccess::offsetExists` and >> `ArrayAccess::offsetGet` methods into a separate `ArrayAccessRead` >> interface (name can be different) and allow read operations `$exists = >> isset($object['key'])` and `$value = $object['key']` for objects of classes >> that implement this interface. `ArrayAccess` will then extend >> `ArrayAccessRead` and add the remaining 2 methods. Looks like this change >> should not break backward compatibility. >> >> > Please check this: https://externals.io/message/122609#122609 where Gina > analyzed and proposed a solution for this. > It looks like the DimensionReadable is exactly the same thing. Maybe also > DimensionFetchable if you consider returning by reference. > > Maybe the improvement can be done in smaller incremental steps, but I > think it's better to agree on a complete solution for splitting ArrayAccess. > > Regards, > Alex >
Wow! That's a great RFC with thorough analysis and an awesome proposal. Forget about my email 😄. Looking forward to news from Gina.
-- Regards, Valentin Udaltsov