Two new functions array_first() and array_last()

php.internals

David Grudl

2 years ago
PHP lacks two very basic functions for working with arrays: - array_first() returning the first element of an array (or null) - array_last() returning the last element of the array (or null) While PHP has functions that return the first and last keys, array_key_first() and array_key_last(), it does not have more useful functions for values. a) What about reset() and end()? Programmers "abuse" the reset() and end() functions for this purpose. The problem is that these functions are used to move the internal pointer in the array. Which is why they have a name that is inappropriate when used in the sense of "return me the first element". Much worse, they shouldn't to be used to get first/last value, because they have a side effect (i.e. moving the pointer). Further, in the absence of an element, they return the obsolete false and not the currently expected null, which can be combined with the ?? operator. In this they differ from the similar functions array_key_first() and array_key_last(). b) What about $array[array_key_first($array)]? For such basic functions as returning the first and last item in an array, there should be a function in the basic package, not a workaround. Moreover, this requires having the array in a local variable, since $this->getFoo()[array_key_first($this->getFoo())] would be very inefficient and possibly incorrect. c) Two such functions were proposed and rejected during the array_key_first/last RFC (https://wiki.php.net/rfc/array_key_first_last) Yes, that was in 2018. At that time, functions like str_contains() or str_starts_with() wouldn't have even come into existence, just because there was an obscure way to do it without them. I believe we've moved on since then. Today we know how useful it is to use simple, easy-to-understand methods, both for programmers who write and read the code. DG

Nikita Popov

2 years ago
On Sat, Oct 14, 2023, at 20:00, David Grudl wrote:
> PHP lacks two very basic functions for working with arrays: > > - array_first() returning the first element of an array (or null) > - array_last() returning the last element of the array (or null) > > While PHP has functions that return the first and last keys, > array_key_first() and array_key_last(), it does not have more useful > functions for values. > > a) What about reset() and end()? > Programmers "abuse" the reset() and end() functions for this purpose. > The problem is that these functions are used to move the internal > pointer in the array. Which is why they have a name that is > inappropriate when used in the sense of "return me the first element". > > Much worse, they shouldn't to be used to get first/last value, because > they have a side effect (i.e. moving the pointer). > > Further, in the absence of an element, they return the obsolete false > and not the currently expected null, which can be combined with the ?? > operator. In this they differ from the similar functions > array_key_first() and array_key_last(). > > b) What about $array[array_key_first($array)]? > > For such basic functions as returning the first and last item in an > array, there should be a function in the basic package, not a > workaround. Moreover, this requires having the array in a local > variable, since $this->getFoo()[array_key_first($this->getFoo())] > would be very inefficient and possibly incorrect. > > c) Two such functions were proposed and rejected during the > array_key_first/last RFC > (https://wiki.php.net/rfc/array_key_first_last) > > Yes, that was in 2018. At that time, functions like str_contains() or > str_starts_with() wouldn't have even come into existence, just because > there was an obscure way to do it without them. I believe we've moved > on since then. Today we know how useful it is to use simple, > easy-to-understand methods, both for programmers who write and read > the code. > > DG
I'm in favor of adding these. To add to what you already said, because reset/end modify the array, there's a good chance that calling these functions will copy the whole array due to a modification you are not actually interested in. So basically you have the choice between calling end(), which is the wrong thing to do semantically and may be slow, or using $array[array_key_last($array)], which is rather convoluted, and incorrect if the array is potentially empty. Regards, Nikita

Ben Ramsey

2 years ago
> On Oct 14, 2023, at 16:30, Nikita Popov <nikita.ppv@gmail.com> wrote: > > On Sat, Oct 14, 2023, at 20:00, David Grudl wrote: >> PHP lacks two very basic functions for working with arrays: >> >> - array_first() returning the first element of an array (or null) >> - array_last() returning the last element of the array (or null) >> >> While PHP has functions that return the first and last keys, >> array_key_first() and array_key_last(), it does not have more useful >> functions for values. >> >> a) What about reset() and end()? >> Programmers "abuse" the reset() and end() functions for this purpose. >> The problem is that these functions are used to move the internal >> pointer in the array. Which is why they have a name that is >> inappropriate when used in the sense of "return me the first element". >> >> Much worse, they shouldn't to be used to get first/last value, because >> they have a side effect (i.e. moving the pointer). >> >> Further, in the absence of an element, they return the obsolete false >> and not the currently expected null, which can be combined with the ?? >> operator. In this they differ from the similar functions >> array_key_first() and array_key_last(). >> >> b) What about $array[array_key_first($array)]? >> >> For such basic functions as returning the first and last item in an >> array, there should be a function in the basic package, not a >> workaround. Moreover, this requires having the array in a local >> variable, since $this->getFoo()[array_key_first($this->getFoo())] >> would be very inefficient and possibly incorrect. >> >> c) Two such functions were proposed and rejected during the >> array_key_first/last RFC >> (https://wiki.php.net/rfc/array_key_first_last) >> >> Yes, that was in 2018. At that time, functions like str_contains() or >> str_starts_with() wouldn't have even come into existence, just because >> there was an obscure way to do it without them. I believe we've moved >> on since then. Today we know how useful it is to use simple, >> easy-to-understand methods, both for programmers who write and read >> the code. >> >> DG > > I'm in favor of adding these. > > To add to what you already said, because reset/end modify the array, there's a good chance that calling these functions will copy the whole array due to a modification you are not actually interested in. > > So basically you have the choice between calling end(), which is the wrong thing to do semantically and may be slow, or using $array[array_key_last($array)], which is rather convoluted, and incorrect if the array is potentially empty. > > Regards, > Nikita
I’m in favor of these functions, for all the same aforementioned reasons. Cheers, Ben

Pierre

2 years ago
Le 15/10/2023 à 01:11, Ben Ramsey a écrit :
>> On Oct 14, 2023, at 16:30, Nikita Popov <nikita.ppv@gmail.com> wrote: >> >> On Sat, Oct 14, 2023, at 20:00, David Grudl wrote: >>> PHP lacks two very basic functions for working with arrays: >>> >>> - array_first() returning the first element of an array (or null) >>> - array_last() returning the last element of the array (or null) >>> >>> While PHP has functions that return the first and last keys, >>> array_key_first() and array_key_last(), it does not have more useful >>> functions for values. >>> >>> a) What about reset() and end()? >>> Programmers "abuse" the reset() and end() functions for this purpose. >>> The problem is that these functions are used to move the internal >>> pointer in the array. Which is why they have a name that is >>> inappropriate when used in the sense of "return me the first element". >>> >>> Much worse, they shouldn't to be used to get first/last value, because >>> they have a side effect (i.e. moving the pointer). >>> >>> Further, in the absence of an element, they return the obsolete false >>> and not the currently expected null, which can be combined with the ?? >>> operator. In this they differ from the similar functions >>> array_key_first() and array_key_last(). >>> >>> b) What about $array[array_key_first($array)]? >>> >>> For such basic functions as returning the first and last item in an >>> array, there should be a function in the basic package, not a >>> workaround. Moreover, this requires having the array in a local >>> variable, since $this->getFoo()[array_key_first($this->getFoo())] >>> would be very inefficient and possibly incorrect. >>> >>> c) Two such functions were proposed and rejected during the >>> array_key_first/last RFC >>> (https://wiki.php.net/rfc/array_key_first_last) >>> >>> Yes, that was in 2018. At that time, functions like str_contains() or >>> str_starts_with() wouldn't have even come into existence, just because >>> there was an obscure way to do it without them. I believe we've moved >>> on since then. Today we know how useful it is to use simple, >>> easy-to-understand methods, both for programmers who write and read >>> the code. >>> >>> DG >> I'm in favor of adding these. >> >> To add to what you already said, because reset/end modify the array, there's a good chance that calling these functions will copy the whole array due to a modification you are not actually interested in. >> >> So basically you have the choice between calling end(), which is the wrong thing to do semantically and may be slow, or using $array[array_key_last($array)], which is rather convoluted, and incorrect if the array is potentially empty. >> >> Regards, >> Nikita > I’m in favor of these functions, for all the same aforementioned reasons.
Yes please ! array_first() and array_last() are definitely needed. I wrote `foreach ($foo as $value) break;` too many times in my life. array_key_first() and array_key_last() I wouldn't use it much, but they'd probably  find their use cases as well. The first two probably only make sense for a numerically indexed array, so I guess that array_is_list() (whatever the name is, I don't want to bikeshed about naming) would be a good addition as well, that, in my opinion, would be pertinent to add at the same time. Regards, Pierre

Larry Garfield

2 years ago
On Sun, Oct 15, 2023, at 7:40 AM, Pierre wrote:
> The first two probably only make sense for a numerically indexed array, > so I guess that array_is_list() (whatever the name is, I don't want to > bikeshed about naming) would be a good addition as well, that, in my > opinion, would be pertinent to add at the same time.
That has already been done: https://www.php.net/array_is_list --Larry Garfield

Pierre

2 years ago
Le 15/10/2023 à 18:09, Larry Garfield a écrit :
> That has already been done:https://www.php.net/array_is_list > > --Larry Garfield
Oh, I forgot it was accepted and merged, thanks for pointing at it. Cheers, Pierre

Saki Takamachi

2 years ago
Hi Pierre
> The first two probably only make sense for a numerically indexed array
I do not think so. If these are something like "reset/end without side effects", then they should work fine even not numeric indexed array. Regards. Saki

Saki Takamachi

2 years ago
Hi, David Many times I've seen reset() used to meet this requirement. I support this, not only from a side effect standpoint, but also from a readability standpoint. I would also like to add the opinion that it is better because it is simpler than the function name in the original RFC that is being referenced. Best regards. Saki

Saki Takamachi

2 years ago
I came up with the idea of ​​using a signature like array_filter(), and when a callback is passed, "return the first/last element that matches the condition" and "return null if there is no match." The downside to this idea is the loss of simplicity. So I'll leave it up to you whether you want to go with this idea or not. I have no intention of forcing this. Best regards. Saki

Paul Dragoonis

2 years ago
On Sun, 15 Oct 2023, 04:49 Saki Takamachi, <saki@sakiot.com> wrote:
> I came up with the idea of ​​using a signature like array_filter(), and > when a callback is passed, "return the first/last element that matches the > condition" and "return null if there is no match." > > The downside to this idea is the loss of simplicity. So I'll leave it up > to you whether you want to go with this idea or not. I have no intention of > forcing this. > > Best regards. >
I'm in favor of these functions. Right now I am doing: $firstItem = current($array) $secondItem = next($array) Which is simple and works, but really it's just by design that the code hasn't shifted the array pointer yet and I can cheat with current() If the pointer was shifted then I'd have to do reset(), which isn't good. array_first() for the win Many thanks, Paul

Tim Düsterhus

2 years ago
Hi On 10/15/23 05:48, Saki Takamachi wrote:
> I came up with the idea of ​​using a signature like array_filter(), and when a callback is passed, "return the first/last element that matches the condition" and "return null if there is no match."
This would be 'array_find()' and I would be in favor of it, with the caveat that I would want it to work with arbitrary iterables. See this previous thread regarding that topic: https://externals.io/message/118896#118896 Best regards Tim Düsterhus

Ayesh - PHP.Watch

2 years ago
> > PHP lacks two very basic functions for working with arrays: > > - array_first() returning the first element of an array (or null) > - array_last() returning the last element of the array (or null) > > While PHP has functions that return the first and last keys, > array_key_first() and array_key_last(), it does not have more useful > functions for values. > > a) What about reset() and end()? > Programmers "abuse" the reset() and end() functions for this purpose. > The problem is that these functions are used to move the internal > pointer in the array. Which is why they have a name that is > inappropriate when used in the sense of "return me the first element". > > Much worse, they shouldn't to be used to get first/last value, because > they have a side effect (i.e. moving the pointer). > > Further, in the absence of an element, they return the obsolete false > and not the currently expected null, which can be combined with the ?? > operator. In this they differ from the similar functions > array_key_first() and array_key_last(). > > b) What about $array[array_key_first($array)]? > > For such basic functions as returning the first and last item in an > array, there should be a function in the basic package, not a > workaround. Moreover, this requires having the array in a local > variable, since $this->getFoo()[array_key_first($this->getFoo())] > would be very inefficient and possibly incorrect. > > c) Two such functions were proposed and rejected during the > array_key_first/last RFC > (https://wiki.php.net/rfc/array_key_first_last) > > Yes, that was in 2018. At that time, functions like str_contains() or > str_starts_with() wouldn't have even come into existence, just because > there was an obscure way to do it without them. I believe we've moved > on since then. Today we know how useful it is to use simple, > easy-to-understand methods, both for programmers who write and read > the code. > > DG >
I would love to have these functions in PHP as well. With the bikeshed risk, perhaps it makes more sense to have the functions named `array_value_first` and `array_value_last`, because we already have `array_key_first` and `array_key_last` functions?

Unnamed Person

2 years ago
> c) Two such functions were proposed and rejected during the > array_key_first/last RFC > (https://wiki.php.net/rfc/array_key_first_last) > > Yes, that was in 2018. At that time, functions like str_contains() or > str_starts_with() wouldn't have even come into existence, just because > there was an obscure way to do it without them. I believe we've moved > on since then. Today we know how useful it is to use simple, > easy-to-understand methods, both for programmers who write and read > the code.
It's true that sentiment may have shifted in this time. However, a common argument at that time still stands: `null` is not a good sentintenal for failure because the value inside the array very well could have been null. This is not true for the keys. For me personally, I think I would still vote no. I'm not entirely sure about that, but that's how I would lean right now. As it stands, you'd have to write code along the lines of: ```php $key = \array_key_first($array); if ($key === null) { // handle the failure } else { // success $value = $array[$key]; } ``` Yes, it would be slightly nicer if we could do: ```php $value = \array_first($array); if ($value === null) { // handle the failure } else { // success } ``` But I fear in practice people will just omit the error checking. One way around that is to throw an exception. I'm not sure how I feel about that, but I'll think about it.

Robert Landers

2 years ago
On Tue, Oct 17, 2023 at 11:10 AM Levi Morrison via internals <internals@lists.php.net> wrote:
> > > c) Two such functions were proposed and rejected during the > > array_key_first/last RFC > > (https://wiki.php.net/rfc/array_key_first_last) > > > > Yes, that was in 2018. At that time, functions like str_contains() or > > str_starts_with() wouldn't have even come into existence, just because > > there was an obscure way to do it without them. I believe we've moved > > on since then. Today we know how useful it is to use simple, > > easy-to-understand methods, both for programmers who write and read > > the code. > > It's true that sentiment may have shifted in this time. However, a > common argument at that time still stands: `null` is not a good > sentintenal for failure because the value inside the array very well > could have been null. This is not true for the keys. For me > personally, I think I would still vote no. I'm not entirely sure about > that, but that's how I would lean right now. > > As it stands, you'd have to write code along the lines of: > > ```php > $key = \array_key_first($array); > if ($key === null) { > // handle the failure > } else { > // success > $value = $array[$key]; > } > ``` > > Yes, it would be slightly nicer if we could do: > > ```php > $value = \array_first($array); > if ($value === null) { > // handle the failure > } else { > // success > } > ``` > > But I fear in practice people will just omit the error checking. > > One way around that is to throw an exception. I'm not sure how I feel > about that, but I'll think about it. > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php >
How is returning null any different than $array[0] on an empty array? https://3v4l.org/K3gRs Currently, it just outputs a warning, but the result is `null`.

Lynn

2 years ago
On Tue, Oct 17, 2023 at 11:15 AM Robert Landers <landers.robert@gmail.com> wrote:
> On Tue, Oct 17, 2023 at 11:10 AM Levi Morrison via internals > <internals@lists.php.net> wrote: > > How is returning null any different than $array[0] on an empty array? > https://3v4l.org/ <https://3v4l.org/K3gRs>>
> > c) Two such functions were proposed and rejected during the > > array_key_first/last RFC > > (https://wiki.php.net/rfc/array_key_first_last) > > > > Yes, that was in 2018. At that time, functions like str_contains() or > > str_starts_with() wouldn't have even come into existence, just because > > there was an obscure way to do it without them. I believe we've moved > > on since then. Today we know how useful it is to use simple, > > easy-to-understand methods, both for programmers who write and read > > the code. > > It's true that sentiment may have shifted in this time. However, a > common argument at that time still stands: `null` is not a good > sentintenal for failure because the value inside the array very well > could have been null. This is not true for the keys. For me > personally, I think I would still vote no. I'm not entirely sure about > that, but that's how I would lean right now. > > As it stands, you'd have to write code along the lines of: > > ```php > $key = \array_key_first($array); > if ($key === null) { > // handle the failure > } else { > // success > $value = $array[$key]; > } > ``` > > Yes, it would be slightly nicer if we could do: > > ```php > $value = \array_first($array); > if ($value === null) { > // handle the failure > } else { > // success > } > ``` > > But I fear in practice people will just omit the error checking. > > One way around that is to throw an exception. I'm not sure how I feel > about that, but I'll think about it. > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php
> >K3gRs <https://3v4l.org/K3gRs> > > Currently, it just outputs a warning, but the result is `null`. > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php > >
I'm okay with `null` being given back as it's the current behavior of accessing the key as well, which is often checked through `$array[0] ?? null`. Something like an `undefined` type could solve this problem, but personally not a fan of this in Javascript. Maybe `array_has_first` or something could be made, but honestly I would still just check for `null` myself most likely.

Robert Landers

2 years ago
On Tue, Oct 17, 2023 at 11:22 AM Lynn <kjarli@gmail.com> wrote:
> > > > On Tue, Oct 17, 2023 at 11:15 AM Robert Landers <landers.robert@gmail.com> wrote: >> >> On Tue, Oct 17, 2023 at 11:10 AM Levi Morrison via internals >> <internals@lists.php.net> wrote: >> >> How is returning null any different than $array[0] on an empty array? >> https://3v4l.org/> > > > > c) Two such functions were proposed and rejected during the > > > array_key_first/last RFC > > > (https://wiki.php.net/rfc/array_key_first_last) > > > > > > Yes, that was in 2018. At that time, functions like str_contains() or > > > str_starts_with() wouldn't have even come into existence, just because > > > there was an obscure way to do it without them. I believe we've moved > > > on since then. Today we know how useful it is to use simple, > > > easy-to-understand methods, both for programmers who write and read > > > the code. > > > > It's true that sentiment may have shifted in this time. However, a > > common argument at that time still stands: `null` is not a good > > sentintenal for failure because the value inside the array very well > > could have been null. This is not true for the keys. For me > > personally, I think I would still vote no. I'm not entirely sure about > > that, but that's how I would lean right now. > > > > As it stands, you'd have to write code along the lines of: > > > > ```php > > $key = \array_key_first($array); > > if ($key === null) { > > // handle the failure > > } else { > > // success > > $value = $array[$key]; > > } > > ``` > > > > Yes, it would be slightly nicer if we could do: > > > > ```php > > $value = \array_first($array); > > if ($value === null) { > > // handle the failure > > } else { > > // success > > } > > ``` > > > > But I fear in practice people will just omit the error checking. > > > > One way around that is to throw an exception. I'm not sure how I feel > > about that, but I'll think about it. > > > > -- > > PHP Internals - PHP Runtime Development Mailing List > > To unsubscribe, visit: https://www.php.net/unsub.php >> >> >K3gRs >> >> Currently, it just outputs a warning, but the result is `null`. >> >> -- >> PHP Internals - PHP Runtime Development Mailing List >> To unsubscribe, visit: https://www.php.net/unsub.php >> > > I'm okay with `null` being given back as it's the current behavior of accessing the key as well, which is often checked through `$array[0] ?? null`. Something like an `undefined` type could solve this problem, but personally not a fan of this in Javascript. Maybe `array_has_first` or something could be made, but honestly I would still just check for `null` myself most likely.
Huh, that's a good observation Lynn. If I might suggest an API change to `array_value_first` (and a similar one for array_value_last), it would be this: `array_value_first(array $array, string|int|null &$key = null): mixed` where you also get back the key. If you want to know if null is an error or an actual value: $value = array_value_first($array, $key); if($key === null) // handle error else // do something with $value You can also freely ignore the key, if you don't need it or care about error checking. That would save doing two function calls on the same array, just to do some error checking.

A.L.E.C

2 years ago
On 17.10.2023 11:29, Robert Landers wrote:
> $value = array_value_first($array, $key); > if($key === null) // handle error > else // do something with $value > > You can also freely ignore the key, if you don't need it or care about > error checking. That would save doing two function calls on the same > array, just to do some error checking. >
Please, no. What's wrong with count() or empty()? +1 for array_first() and array_last(). The only problem is probably a big BC break. I myself have array_first() defined in my framework.
-- Aleksander Machniak Kolab Groupware Developer [https://kolab.org] Roundcube Webmail Developer [https://roundcube.net] ---------------------------------------------------- PGP: 19359DC1 # Blog: https://kolabian.wordpress.com

Robert Landers

2 years ago
On Tue, Oct 17, 2023 at 11:34 AM Aleksander Machniak <alec@alec.pl> wrote:
> > On 17.10.2023 11:29, Robert Landers wrote: > > $value = array_value_first($array, $key); > > if($key === null) // handle error > > else // do something with $value > > > > You can also freely ignore the key, if you don't need it or care about > > error checking. That would save doing two function calls on the same > > array, just to do some error checking. > > > > Please, no. What's wrong with count() or empty()? > > +1 for array_first() and array_last(). The only problem is probably a > big BC break. I myself have array_first() defined in my framework. > > -- > Aleksander Machniak > Kolab Groupware Developer [https://kolab.org] > Roundcube Webmail Developer [https://roundcube.net] > ---------------------------------------------------- > PGP: 19359DC1 # Blog: https://kolabian.wordpress.com > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php >
Hey Aleksander,
> Please, no. What's wrong with count() or empty()?
Nothing. Why not either one? You don't have to use the $key variable and you can use count() or empty(), but for me personally, it makes a lot of sense.

Robert Landers

2 years ago
On Tue, Oct 17, 2023 at 11:37 AM Robert Landers <landers.robert@gmail.com> wrote:
> > On Tue, Oct 17, 2023 at 11:34 AM Aleksander Machniak <alec@alec.pl> wrote: > > > > On 17.10.2023 11:29, Robert Landers wrote: > > > $value = array_value_first($array, $key); > > > if($key === null) // handle error > > > else // do something with $value > > > > > > You can also freely ignore the key, if you don't need it or care about > > > error checking. That would save doing two function calls on the same > > > array, just to do some error checking. > > > > > > > Please, no. What's wrong with count() or empty()? > > > > +1 for array_first() and array_last(). The only problem is probably a > > big BC break. I myself have array_first() defined in my framework. > > > > -- > > Aleksander Machniak > > Kolab Groupware Developer [https://kolab.org] > > Roundcube Webmail Developer [https://roundcube.net] > > ---------------------------------------------------- > > PGP: 19359DC1 # Blog: https://kolabian.wordpress.com > > > > -- > > PHP Internals - PHP Runtime Development Mailing List > > To unsubscribe, visit: https://www.php.net/unsub.php > > > > Hey Aleksander, > > > Please, no. What's wrong with count() or empty()? > > Nothing. Why not either one? You don't have to use the $key variable > and you can use count() or empty(), but for me personally, it makes a > lot of sense.
Ah, I just realized why it makes a lot of sense, and that is when Fibers get involved. The value and key could change underneath you from one function call to another. $key = array_key_first($this-array); // call something that suspends a fiber and results in $this->array being mutated $value = array_value_first($this->array); // $value and $key may now point to two totally separate things. I've been bitten by this with Fibers a few times now (or things very similar to it). Having a way to atomically get $key and $value would be a boon, not a hindrance. Robert Landers Software Engineer Utrecht NL

Ken Guest

2 years ago
Having array_value_first and array_value_last to match the existing array_key_first and array_key_last functions make sense, and would seem to me to be more intuitive than function names that would not match that scheme. On Tue, 17 Oct 2023 at 10:41, Robert Landers <landers.robert@gmail.com> wrote:
> On Tue, Oct 17, 2023 at 11:37 AM Robert Landers > <landers.robert@gmail.com> wrote: > > > > On Tue, Oct 17, 2023 at 11:34 AM Aleksander Machniak <alec@alec.pl> > wrote: > > > > > > On 17.10.2023 11:29, Robert Landers wrote: > > > > $value = array_value_first($array, $key); > > > > if($key === null) // handle error > > > > else // do something with $value > > > > > > > > You can also freely ignore the key, if you don't need it or care > about > > > > error checking. That would save doing two function calls on the same > > > > array, just to do some error checking. > > > > > > > > > > Please, no. What's wrong with count() or empty()? > > > > > > +1 for array_first() and array_last(). The only problem is probably a > > > big BC break. I myself have array_first() defined in my framework. > > > > > > -- > > > Aleksander Machniak > > > Kolab Groupware Developer [https://kolab.org] > > > Roundcube Webmail Developer [https://roundcube.net] > > > ---------------------------------------------------- > > > PGP: 19359DC1 # Blog: https://kolabian.wordpress.com > > > > > > -- > > > PHP Internals - PHP Runtime Development Mailing List > > > To unsubscribe, visit: https://www.php.net/unsub.php > > > > > > > Hey Aleksander, > > > > > Please, no. What's wrong with count() or empty()? > > > > Nothing. Why not either one? You don't have to use the $key variable > > and you can use count() or empty(), but for me personally, it makes a > > lot of sense. > > Ah, I just realized why it makes a lot of sense, and that is when > Fibers get involved. The value and key could change underneath you > from one function call to another. > > $key = array_key_first($this-array); > > // call something that suspends a fiber and results in $this->array > being mutated > > $value = array_value_first($this->array); > > // $value and $key may now point to two totally separate things. > > I've been bitten by this with Fibers a few times now (or things very > similar to it). > > Having a way to atomically get $key and $value would be a boon, not a > hindrance. > > Robert Landers > Software Engineer > Utrecht NL > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php >
-- http://about.me/kenguest/

Aimeos | Norbert Sendetzky

2 years ago
On 17.10.23 17:16, Ken Guest wrote:
> Having array_value_first and array_value_last to match the existing > array_key_first and array_key_last functions make sense, and would seem to > me to be more intuitive than function names that would not match that > scheme.
Please don't make things more complicated than they should be. Functions names should be short and memorable and array_first() and array_last() are perfect. No need for array_value_first() and array_value_last() just for the sake of matching with array_key_first() and array_key_last() functions. Furthermore, returning NULL if the array contains no element is all we need in daily life because most often it doesn't matter if the array is empty or the first value is a NULL value. If it does, checking the array with empty() or using array_filter() is enough. No exceptions, warnings and notices please! Always think of how you would use the functions in your own projects to write short and elegant code, not about all the special cases that should be handled separately. Best, Norbert
> On Tue, 17 Oct 2023 at 10:41, Robert Landers <landers.robert@gmail.com> > wrote: > >> On Tue, Oct 17, 2023 at 11:37 AM Robert Landers >> <landers.robert@gmail.com> wrote: >>> >>> On Tue, Oct 17, 2023 at 11:34 AM Aleksander Machniak <alec@alec.pl> >> wrote: >>>> >>>> On 17.10.2023 11:29, Robert Landers wrote: >>>>> $value = array_value_first($array, $key); >>>>> if($key === null) // handle error >>>>> else // do something with $value >>>>> >>>>> You can also freely ignore the key, if you don't need it or care >> about >>>>> error checking. That would save doing two function calls on the same >>>>> array, just to do some error checking. >>>>> >>>> >>>> Please, no. What's wrong with count() or empty()? >>>> >>>> +1 for array_first() and array_last(). The only problem is probably a >>>> big BC break. I myself have array_first() defined in my framework. >>>> >>>> -- >>>> Aleksander Machniak >>>> Kolab Groupware Developer [https://kolab.org] >>>> Roundcube Webmail Developer [https://roundcube.net] >>>> ---------------------------------------------------- >>>> PGP: 19359DC1 # Blog: https://kolabian.wordpress.com >>>> >>>> -- >>>> PHP Internals - PHP Runtime Development Mailing List >>>> To unsubscribe, visit: https://www.php.net/unsub.php >>>> >>> >>> Hey Aleksander, >>> >>>> Please, no. What's wrong with count() or empty()? >>> >>> Nothing. Why not either one? You don't have to use the $key variable >>> and you can use count() or empty(), but for me personally, it makes a >>> lot of sense. >> >> Ah, I just realized why it makes a lot of sense, and that is when >> Fibers get involved. The value and key could change underneath you >> from one function call to another. >> >> $key = array_key_first($this-array); >> >> // call something that suspends a fiber and results in $this->array >> being mutated >> >> $value = array_value_first($this->array); >> >> // $value and $key may now point to two totally separate things. >> >> I've been bitten by this with Fibers a few times now (or things very >> similar to it). >> >> Having a way to atomically get $key and $value would be a boon, not a >> hindrance. >> >> Robert Landers >> Software Engineer >> Utrecht NL >> >> -- >> PHP Internals - PHP Runtime Development Mailing List >> To unsubscribe, visit: https://www.php.net/unsub.php >> > >
-- Norbert Sendetzky Aimeos GmbH Rennbahnstr. 32 DE-22111 Hamburg E-Mail: norbert@aimeos.com Phone: +49 40 8668 4492 Web: aimeos.com Trade register: District court Hamburg HRB 143090 Managing director: Norbert Sendetzky VAT ID: DE302287839

Michael Cordover

2 years ago
On Tue, Oct 17, 2023, at 05:10, Levi Morrison via internals wrote:
> It's true that sentiment may have shifted in this time. However, a > common argument at that time still stands: `null` is not a good > sentintenal for failure because the value inside the array very well > could have been null.
What about a signature like: ```php array_first(array $array, mixed $value_if_missing = null); ``` That would let you specify your own sentinel (or default) where appropriate, without losing the convenience of this function. mjec

Saki Takamachi

2 years ago
> What about a signature like: > > ```php > array_first(array $array, mixed $value_if_missing = null); > ``` > > That would let you specify your own sentinel (or default) where appropriate, without losing the convenience of this function.
This is a problem that should be addressed in your application. ``` array_first($arr) ?? $initial ``` I personally think we should make the effort to write it this way and not have to support initial values ​​at the language level. Regards. Saki

Michael Cordover

2 years ago
On Tue, Oct 17, 2023, at 12:19, Saki Takamachi wrote:
>> What about a signature like: >> >> ```php >> array_first(array $array, mixed $value_if_missing = null); >> ``` >> >> That would let you specify your own sentinel (or default) where appropriate, without losing the convenience of this function. > > This is a problem that should be addressed in your application. > > ``` > array_first($arr) ?? $initial > ``` > > I personally think we should make the effort to write it this way and > not have to support initial values ​​at the language level.
The problem Levi mentioned is that there's ambiguity in this construction: if the valid data domain for elements of `$arr` includes `null`, then you can't tell whether the null comes from the array being empty, or from its first value being null. In other words, there exists application code where using `??` in this way is unsuitable. I can think of three approaches for dealing with this, resulting in application code like: ``` $value = array_first($arr, $default); $value = count($arr) > 0 ? array_first($arr) : $default; try { $value = array_first($arr); } catch (OutOfBoundsException $e) { $value = $default; } ``` I think the first of those - what I initially suggested - is the cleanest. mjec

Saki Takamachi

2 years ago
I see now, that makes sense. There is also a technique to make the return value `[$key => $value]` instead of just a value, but this loses simplicity. Thanks. Saki

Brandon Jackson

2 years ago
> There is also a technique to make the return value `[$key => $value]` instead of just a value, but this loses simplicity.
Hmm, since the naming array_first and array_last doesn't clarify that it's returning a key or a value. What if it returned both as ?[key, value]. That opens quite a few use possibilities: $first = array_first($array); $value = $first[1] ?? throw new Exception(); [,$value] = array_first($array) ?? [null, null]; [,$value] = array_first($array) ?? throw new Exception();

Saki Takamachi

2 years ago
Since reset() and end() return false when the array is empty, in a sense, there is an idea that there is no need to take such strict care of the return value. If you were to take proper care, you would probably specify a default value or throw an exception, as has already been suggested. However, specifying a default value is not very smart in my opinion. The fact that what value is considered to be "unable to obtain" changes depending on the situation causes some complexity. And when dealing with an array whose values ​​are completely unknown, it becomes necessary to "hope" that the values ​​do not conflict with the default values. Can the following signature meet your requirements? Or will it become too complicated? ``` // arrar_first(array $arr, bool &$has_value) $value = array_first($arr, $has_value); if ($has_value) { // array has items // $value is mixed } else { // array is empty // $value === null } ``` Regards. Saki

Saki Takamachi

2 years ago
I thought of it after sending the email, so I'll post it again. By combining my two ideas, I think I can come up with a smarter proposal. ``` array_first(array $array, int|string &$key = null) ``` If you want to accurately determine whether an array is empty or not, you can satisfy your request by checking if the key is null. Users who do not think accurate determination is necessary can omit the second argument. And if you also want a key, it can fulfill that request as well. Regards. Saki

Deleu

2 years ago
On Tue, Oct 17, 2023 at 3:43 PM Brandon Jackson <brandonja991@gmail.com> wrote:
> > There is also a technique to make the return value `[$key => $value]` > instead of just a value, but this loses simplicity. > > Hmm, since the naming array_first and array_last doesn't clarify that > it's returning a key or a value. What if it returned both as ?[key, > value]. > > That opens quite a few use possibilities: > $first = array_first($array); > $value = $first[1] ?? throw new Exception(); > > [,$value] = array_first($array) ?? [null, null]; > [,$value] = array_first($array) ?? throw new Exception(); >
This function signature can be accomplished by userland once we have `array_key_first()` and `array_first()`. It's much better to keep `array_first()` as simple as possible and let everyone build their own approach to go about it since we have so many approaches.
-- Marco Deleu

Robert Landers

2 years ago
On Wed, Oct 18, 2023 at 5:26 AM Deleu <deleugyn@gmail.com> wrote:
> > On Tue, Oct 17, 2023 at 3:43 PM Brandon Jackson <brandonja991@gmail.com> > wrote: > > > > There is also a technique to make the return value `[$key => $value]` > > instead of just a value, but this loses simplicity. > > > > Hmm, since the naming array_first and array_last doesn't clarify that > > it's returning a key or a value. What if it returned both as ?[key, > > value]. > > > > That opens quite a few use possibilities: > > $first = array_first($array); > > $value = $first[1] ?? throw new Exception(); > > > > [,$value] = array_first($array) ?? [null, null]; > > [,$value] = array_first($array) ?? throw new Exception();
Hey Marco,
> This function signature can be accomplished by userland once we have > `array_key_first()` and `array_first()`.
This would always mean you have to keep them right next to each other, it would be a best practice to do so and to split them up should be a code smell in any static analysis. There is no way to tell if a Fiber is involved in any function call in PHP, thus if you split them apart and call a function, it is possible that your current Fiber is suspended and another Fiber mutates the variable you are referencing (this is especially true in Classes, not so much in pure functions). Since they would always have to be right next to each other, it is easier to just combine them into a single atomic function call, which would negate the need for static analysis to be involved or surprises.
> It's much better to keep > `array_first()` as simple as possible and let everyone build their own > approach to go about it since we have so many approaches.
There is only one right approach that prevents Fibers from messing up your day, and it would be considerable boilerplate code that you'd have to type every time, as well as involve static analysis and watch for "people who don't know" better in code reviews. Robert Landers Software Engineer Utrecht NL

Deleu

2 years ago
On Wed, Oct 18, 2023 at 4:31 AM Robert Landers <landers.robert@gmail.com> wrote:
> On Wed, Oct 18, 2023 at 5:26 AM Deleu <deleugyn@gmail.com> wrote: > > > > On Tue, Oct 17, 2023 at 3:43 PM Brandon Jackson <brandonja991@gmail.com> > > wrote: > > > > > > There is also a technique to make the return value `[$key => $value]` > > > instead of just a value, but this loses simplicity. > > > > > > Hmm, since the naming array_first and array_last doesn't clarify that > > > it's returning a key or a value. What if it returned both as ?[key, > > > value]. > > > > > > That opens quite a few use possibilities: > > > $first = array_first($array); > > > $value = $first[1] ?? throw new Exception(); > > > > > > [,$value] = array_first($array) ?? [null, null]; > > > [,$value] = array_first($array) ?? throw new Exception(); > > > Hey Marco, > > > This function signature can be accomplished by userland once we have > > `array_key_first()` and `array_first()`. > > This would always mean you have to keep them right next to each other, > it would be a best practice to do so and to split them up should be a > code smell in any static analysis.
"You" (general you) don't always have to keep them right next to each other. Each function is self-sufficient and independent. Maybe on your personal bubble you might need to always keep them next to each other, which is why I suggested creating your own userland function that returns key and value together.
> There is no way to tell if a Fiber > is involved in any function call in PHP, thus if you split them apart > and call a function, it is possible that your current Fiber is > suspended and another Fiber mutates the variable you are referencing > (this is especially true in Classes, not so much in pure functions). >
I might be completely wrong here, but on my personal bubble, I consider Fibers to be a corner (a fraction) of PHP compared to non-Fibers PHP. Although Fibers took the approach to not "paint" [what color is] your function, it doesn't mean that Fibers can be used without taking precaution, as with any new tool.
> Since they would always have to be right next to each other, it is > easier to just combine them into a single atomic function call, which > would negate the need for static analysis to be involved or surprises. > > > It's much better to keep > > `array_first()` as simple as possible and let everyone build their own > > approach to go about it since we have so many approaches. > > There is only one right approach that prevents Fibers from messing up > your day, and it would be considerable boilerplate code that you'd > have to type every time, as well as involve static analysis and watch > for "people who don't know" better in code reviews. >
You say only one approach, but a return signature of `: [$key, $value]` or the `array_key(array $array, &$key = null) ` makes it at least 2 approaches that would be fibers-safe, no? This is a discussion about an extremely basic functionality that PHP hasn't introduced up until now. I think it's an extremely great addition, but requires to focus first on the most basic aspect of it. Literally every beginner, mid-level, experienced and most senior PHP developers will work with PHP arrays on way or another. As such, a basic functionality like this should remain as basic as possible. If needed, PHP can port more helper functions into the core to cater for Fibers in the future. In my opinion, the only problem is the ambiguity of returning `null` which might mean the array is empty or might mean the first value is truly null. If we get a warning box on PHP Docs recommending people to pair this with `empty()` before using it, it gives users coverage for everything they will need most of the time. Personally, I think I'd prefer the function to throw an exception than to return `null` when array is empty to avoid ambiguity and force folks to use `empty()`, but that would also mean complicating the function more due to edge cases, which as I stated in this email, I'd rather have the simplest thing possible and let userland fill in the additional complexities needed.
-- Marco Deleu

Brandon Jackson

2 years ago
> This function signature can be accomplished by userland once we have `array_key_first()` and `array_first()`. It's much better to keep `array_first()` as simple as possible and let everyone build their own approach to go about it since we have so many approaches.
The goal wasn't necessarily to keep them together. The goal was to introduce an arguably simple way to: 1. Be able to get the first/last value of an array. 2. Know if the value was actually in existence or not, rather than just blindly returning null when it could be a valid value. 3. Accompany multiple use cases like needing to return a default if not found or throwing an exception. 4. Offer a way to know if the value existed or not and act accordingly without additional logic checking the key. 5. Address the seeming genericness of the function name. * If I were someone who seen the name for the first time. I'd see it and ask array_first what? And proceed to the docs. The different approaches are trying to figure out the best way to know whether the result was the actual value from the array or some baked in language default null. I get your desire to keep things simple, but IMO returning a value that does not conflict with possibly valid values or somehow indicates the value was not present is important, and should come before simplicity. Which likely means involving the key somehow.

Deleu

2 years ago
On Wed, Oct 18, 2023 at 10:11 AM Brandon Jackson <brandonja991@gmail.com> wrote:
> > I get your desire to keep things simple, but IMO returning a value > that does not conflict with possibly valid values or somehow indicates > the value was not present is important, and should come before > simplicity. Which likely means involving the key somehow. >
The only portion in your email I disagree with is this ending. I believe there are enough use-cases where if the first value is "valid null" or "default null" it won't matter. The developer will treat them both the same. Perhaps you disagree with this and want to avoid ambiguity at all costs. My proposal to avoid ambiguity would be throwing an exception instead of involving the key because involving the key can be a composition between `array_first()`* and `array_key_first()`. Although I would prefer the function to throw, I think it will have the same effect as this key discussion: complicate something that can be simple. If the developer needs to distinguish between "default null" and "value null", they are able to do so by running `empty()` on the array prior to asking for `array_first()`. It's actually better than a try/catch, to be honest. Ultimately, there's 2 parallel discussion that somewhat intertwine themselves: Fibers ("async" code) and ambiguity ("value null" vs "default null") and while there are options that may cater for both of them, there are also options that cater only for each of them individually. Trying to over-pollute a function as simple as `array_first()` to cater for these edge cases is where I think the problem is because userland will always be able to tackle these issues by wrapping the basic functionality provided by core. * If naming is an issue to you, I'd also be fine with `array_value_first()`.
-- Marco Deleu