Greetings internals,
I would like to have your opinion on being able to type hint arrays and
objects which implement
array-like interfaces (notably ArrayAccess, Countable, and Iterator) as
currently if a function /method only needs one specific feature of an array
and is willing to accept array-like objects.
There are some rather repetitive boilerplate and the impossibility of using
type hints.
An example of such a function, (where $arrayLike could be custom session
object) :
/** ArrayAccess|array $arrayLike */
public function checkCSRF($session) {
if (!is_array($session) && !($session instanceof ArrayAccess)) {
throw new Exception();
}
// Check token
if (!isset($session['CSRF']) {
throw new Exception();
}
// Do some more stuff ...
}
As it can be seen this function/method doesn't need any of the other
properties of an array
such as Countability or Traversability to do its job.
However, in the current state of PHP, it is impossible to accept array-like
objects without
writing the initial if statement.
PHP does have the pseudo-type iterable which allows passing Traversable
objects as well as
arrays. Moreover, the count function accepts objects which implement the
Countable interface.
This is achieved with specials checks within the function [1].
My knowledge in C is extremely limited and basic but I see three possible
implementations:
First one, which seems rather impractical/impossible, is to make arrays
"implement" these
interfaces by possibly paving the way to object-like arrays.
However, this would probably mean a major rewrite in most parts of the
engine and impact
performance as arrays won't be a basic data structure anymore.
(Or maybe only some changes to these magic interfaces in zend_interfaces.c
are needed? [2])
The second one, adding new pseudo-types like iterable. [3]
This is probably one of the simplest solutions however I don't know how
ArrayAccess would be
named. Moreover, it seems the least "scalable" in case PHP adds a new
interface where arrays
can be used (something like Comparable or Sortable comes to mind)
Thirdly, adding a special check during type hinting against these
interfaces that allows arrays.
I am not sure where this should be implemented; possibly in
Zend/zend_inheritance.c [4]
or within the lexer.
However, as I don't know if other parts of the engine would need to be
updated I've made a list
of possible impacted areas of the engine which comes with this proposal,
namely:
- Argument type hints
- Return types
- Typed properties
- Covariance and Contravariance
Possible disadvantages:
- Performance impact as every object type hint now needs to go through
the special check - This could/should be implemented with object-like arrays
I can't see any other disadvantages so if someone sees some if they could
raise them this
would be greatly appreciated.
Future scope:
Possibly changing signatures of some array_* functions? However, they would
probably sill
need to have separate code paths like count. [1]
Best regards
George P. Banyard
[1] Count function
https://github.com/php/php-src/blob/master/ext/standard/array.c#L772
[2] "Magic" interfaces
https://github.com/php/php-src/blob/master/Zend/zend_interfaces.c#L579
[3] Fake engine types
https://github.com/php/php-src/blob/master/Zend/zend_types.h#L435
[4] Type hint check
https://github.com/php/php-src/blob/master/Zend/zend_inheritance.c#L180