# Consolidation of Traversable and array operations

- Thread: https://externals.io/message/87181
- Original archive: https://news-web.php.net/php.internals/87181
- Started by Tjerk Meesters on 2015-07-15T11:28:28+00:00
- Messages: 13
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #87181 — Tjerk Meesters — 2015-07-15T11:28:28+00:00

URL: https://externals.io/message/87181#87181

Hi!

A few weeks ago I resurrected a two year old proposal for adding two array
functions, namely array_every() and array_some(), modelled after their
JavaScript equivalent.

https://github.com/php/php-src/pull/1385

The most notable comment was that it would be nice to support Traversable
as well as arrays; instead of only supporting this for my own functions,
I've generalised this so that other functions can take advantage of this as
well. These are the additions:

1. A ZPP argument; the "t" (for traversable) argument type has been added
that checks for either an array or implementation of zend_ce_traversable.

2. A generic iteration function, called php_traverse(); it accepts:
  a. the zval* to iterate over,
  b. a step-wise function that receives the value and key, and returns a
boolean that determines whether iteration should continue or not,
  c. a traversal mode (only values, or keys and values),
  d. a context that's sent to the step-wise function.

3. A concrete implementation of a step-wise iteration function,
 php_traverse_until, that gets called as part of array_every() and
array_some().

The implementation of above proposal can be found in the PR itself. With
more functions adopting this idea, you could see this work:

var_dump(array_reduce((function() {
    yield 1;
    yield 2;
    yield 3;
})(), function($total, $current) {
    return $total + $current;
}, 0); // int(6)

Let me know what you think!

---

## #87183 — Michael Wallner — 2015-07-15T11:49:26+00:00

URL: https://externals.io/message/87181#87183 · In reply to: #87181

> Hi!
> 
> A few weeks ago I resurrected a two year old proposal for adding two array
> functions, namely array_every() and array_some(), modelled after their
> JavaScript equivalent.
> 
> https://github.com/php/php-src/pull/1385
> 
> ...
> 
> Let me know what you think!
> 

Sounds awesome!

-- 
Regards,
Mike

---

## #87186 — johannes@schlueters.de — 2015-07-15T13:43:58+00:00

URL: https://externals.io/message/87181#87186 · In reply to: #87181

Hi,


> The most notable comment was that it would be nice to support Traversable
> as well as arrays; instead of only supporting this for my own functions,
> I've generalised this so that other functions can take advantage of this as
> well. These are the additions:
> 
> 1. A ZPP argument; the "t" (for traversable) argument type has been added
> that checks for either an array or implementation of zend_ce_traversable.
> 
> 2. A generic iteration function, called php_traverse(); it accepts:
>   a. the zval* to iterate over,
>   b. a step-wise function that receives the value and key, and returns a
> boolean that determines whether iteration should continue or not,
>   c. a traversal mode (only values, or keys and values),
>   d. a context that's sent to the step-wise function.

I really like this concept to unify by access pattern, hiding the actual
implementation!

> 3. A concrete implementation of a step-wise iteration function,
>  php_traverse_until, that gets called as part of array_every() and
> array_some().

I wonder if we can find a better naming scheme. For some array_
functions this will work, others not. This again feeds the "PHP is so
inconsistent"-trolls. At the moment I'm leaning towards simply using
every() and some_of() without reference to a type. Or maybe introduce,
to restart the namespace-debate, php\every(), php\search(), php
\someOf(), php\product(), etc. and deprecate `array_search()` etc.

johannes

---

## #87187 — Julien Pauli — 2015-07-15T14:31:08+00:00

URL: https://externals.io/message/87181#87187 · In reply to: #87186

On Wed, Jul 15, 2015 at 3:43 PM, Johannes Schlüter <johannes@schlueters.de>
wrote:

> Hi,
>
> 
> > […]
> as
> > […]
>
> I really like this concept to unify by access pattern, hiding the actual
> implementation!
>
> > […]
>
> I wonder if we can find a better naming scheme. For some array_
> functions this will work, others not. This again feeds the "PHP is so
> inconsistent"-trolls. At the moment I'm leaning towards simply using
> every() and some_of() without reference to a type. Or maybe introduce,
> to restart the namespace-debate, php\every(), php\search(), php
> \someOf(), php\product(), etc. and deprecate `array_search()` etc.
>
> johannes
>
>
Nikic designed "Iter" some time ago, when he finished adding Generators to
PHP.
Perhaps some ideas could be taken from it.
https://github.com/nikic/iter

I suggest writing an RFC and target 8.0, while the deprecations could
target 7.X

Also, there has been an open subject for ages about how could we uniform
array and Traversable internally, as well as from PHP user land (the main
subject was then to add support for ArrayAccess to every array_***() PHP
function).

I'm happy this bumps the subject up , as it is quite a hot topic.


Julien Pauli

---

## #87188 — Levi Morrison — 2015-07-15T19:39:05+00:00

URL: https://externals.io/message/87181#87188 · In reply to: #87187

> On Wed, Jul 15, 2015 at 3:43 PM, Johannes Schlüter <johannes@schlueters.de>
> wrote:
>
> > […]
> Nikic designed "Iter" some time ago, when he finished adding Generators to
> PHP.
> Perhaps some ideas could be taken from it.
> https://github.com/nikic/iter
>
> I suggest writing an RFC and target 8.0, while the deprecations could
> target 7.X
>
> Also, there has been an open subject for ages about how could we uniform
> array and Traversable internally, as well as from PHP user land (the main
> subject was then to add support for ArrayAccess to every array_***() PHP
> function).
>
> I'm happy this bumps the subject up , as it is quite a hot topic.

Do note that the union types RFC would also alleviate some of this
pain for user-land functions, since `array | Traversable` would cover
the required access pattern. I think this is a superior approach
myself, but I may be a bit biased as I am authoring that proposal:
https://wiki.php.net/rfc/union_types

---

## #87189 — Rowan Collins — 2015-07-15T19:53:23+00:00

URL: https://externals.io/message/87181#87189 · In reply to: #87188

>Do note that the union types RFC would also alleviate some of this
>pain for user-land functions, since `array | Traversable` would cover
>the required access pattern. I think this is a superior approach
>myself, but I may be a bit biased as I am authoring that proposal:
>https://wiki.php.net/rfc/union_types

I like the idea of union types in general, but have always felt that a typehint of Traversable should accept arrays as a matter of course. The only thing such a typehint guarantees is that foreach will work (there are no methods defined that can be called directly), and an array meets that condition. The only difference I can see is in the passing / mutability behaviour of objects vs non-objects.

Regards,
-- 
Rowan Collins
[IMSoP]

---

## #87190 — Benjamin Eberlei — 2015-07-15T20:19:53+00:00

URL: https://externals.io/message/87181#87190 · In reply to: #87189

On Wed, Jul 15, 2015 at 9:53 PM, Rowan Collins <rowan.collins@gmail.com>
wrote:

> 
> > […]
>
> I like the idea of union types in general, but have always felt that a
> typehint of Traversable should accept arrays as a matter of course. The
> only thing such a typehint guarantees is that foreach will work (there are
> no methods defined that can be called directly), and an array meets that
> condition. The only difference I can see is in the passing / mutability
> behaviour of objects vs non-objects.
>

But instanceof and anything related to Reflection or get_class or relevant
code will fail on array.

>
> Regards,
> --
> Rowan Collins
> [IMSoP]

---

## #87194 — Rowan Collins — 2015-07-16T09:26:31+00:00

URL: https://externals.io/message/87181#87194 · In reply to: #87190

Benjamin Eberlei wrote on 15/07/2015 21:19:
>
>
> On Wed, Jul 15, 2015 at 9:53 PM, Rowan Collins 
> <rowan.collins@gmail.com <mailto:rowan.collins@gmail.com>> wrote:
>
>     On 15 July 2015 20:39:05 GMT+01:00, Levi Morrison <levim@php.net
>     <mailto:levim@php.net>> wrote:
> > […]
>
>     I like the idea of union types in general, but have always felt
>     that a typehint of Traversable should accept arrays as a matter of
>     course. The only thing such a typehint guarantees is that foreach
>     will work (there are no methods defined that can be called
>     directly), and an array meets that condition. The only difference
>     I can see is in the passing / mutability behaviour of objects vs
>     non-objects.
>
>
> But instanceof and anything related to Reflection or get_class or 
> relevant code will fail on array.


Ah, yes, I hadn't thought of reflection type things. I don't think 
instanceof would be a problem, because checking for any class or 
interface other than Traversable would correctly return false; not sure 
if it would make sense for "array() instanceof Traversable" to return 
true or not...

---

## #87195 — Michael Wallner — 2015-07-16T10:38:45+00:00

URL: https://externals.io/message/87181#87195 · In reply to: #87194

> Benjamin Eberlei wrote on 15/07/2015 21:19:
> > […]
> 
> 
> Ah, yes, I hadn't thought of reflection type things. I don't think
> instanceof would be a problem, because checking for any class or
> interface other than Traversable would correctly return false; not sure
> if it would make sense for "array() instanceof Traversable" to return
> true or not...
> 

Maybe some pseudotype like callable (e.g. iteratable) makes more sense then?


-- 
Regards,
Mike

---

## #87199 — Tjerk Meesters — 2015-07-16T13:08:42+00:00

URL: https://externals.io/message/87181#87199 · In reply to: #87195

Hi!


> 
> > […]
>
> Maybe some pseudotype like callable (e.g. iteratable) makes more sense
> then?
>

I'm okay with a pseudo type.

My opinion on the matter at this point is such that I care more about
providing an API of sorts to support both kinds of structures, so that any
 developer can write an extension that can leverage this capability and
make this available in user-land.

Having array_some() and array_every() support this doesn't have to be
documented for all I care, if anything it serves as an example of what can
be done.

The most immediate feedback I would like is:
a) whether it's useful to add as an API,
b) a review of the code in `php_traversal.[ch]`


>
> --
> Regards,
> Mike

---

## #87200 — Levi Morrison — 2015-07-16T15:23:17+00:00

URL: https://externals.io/message/87181#87200 · In reply to: #87195

> 
> > […]
>
> Maybe some pseudotype like callable (e.g. iteratable) makes more sense then?

People have talked about creating types like so:

type Iterable = array | Traversable;

which could then be used as normal:

function foo(Iterable $f);

I understand that this is the second feature I have mentioned in this
train of thought that has not yet be officially proposed, but I think
it's relevant. Why special case a pseudo-type if we can have a generic
way of making them in user-land?

---

## #87201 — Rowan Collins — 2015-07-16T15:42:20+00:00

URL: https://externals.io/message/87181#87201 · In reply to: #87200

Levi Morrison wrote on 16/07/2015 16:23:

> People have talked about creating types like so:
>
> type Iterable = array | Traversable;
>
> which could then be used as normal:
>
> function foo(Iterable $f);

I kind of like this idea.

> Why special case a pseudo-type if we can have a generic
> way of making them in user-land?

Well, for the same reason as large amounts of the core library exist 
(and PHP's is small compared to some): standardisation and ease of use. 
I think "array | Traversable" is a common enough use-case that it 
deserves a built-in name, even if a userland naming system is available.

Regards,
-- 
Rowan Collins
[IMSoP]

---

## #87202 — Levi Morrison — 2015-07-16T16:01:37+00:00

URL: https://externals.io/message/87181#87202 · In reply to: #87201

> Levi Morrison wrote on 16/07/2015 16:23:
>
> > […]
>
>
> I kind of like this idea.
>
> > […]
>
>
> Well, for the same reason as large amounts of the core library exist (and
> PHP's is small compared to some): standardisation and ease of use. I think
> "array | Traversable" is a common enough use-case that it deserves a
> built-in name, even if a userland naming system is available.

I assume if `type Iterable = array | Traversable` can be built in
user-land then it will be done using the same mechanisms in core
(meaning it wouldn't be a special case or one-off type).
