-
Notifications
You must be signed in to change notification settings - Fork 7.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add is_list function #4886
Add is_list function #4886
Conversation
This function tests if an array contains only sequential integer keys. While this isn't an official type, this usage is consistent with the community usage of "list" as an annotation type, cf. https://psalm.dev/docs/annotating_code/type_syntax/array_types/#lists
zend_string *str_idx; | ||
|
||
ZEND_PARSE_PARAMETERS_START(1, 1) | ||
Z_PARAM_ZVAL(arg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you could use Z_PARAM_ARRAY_HT()
here, to get arrval
without further ado.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would make the function throw an error when passed a non-array argument:
Fatal error: Uncaught TypeError: is_list() expects parameter 1 to be array, null given
My intention was to make is_list
behave like the other is_
type-checking functions, which quietly return false when passed a type different from the one they're checking for.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@duskwuff AFAIK, you could also use the following if you want to achieve an is_*
alike behaviour:
ZEND_PARSE_PARAMS_START_EX(ZEND_PARSE_PARAMS_QUIET, 1, 1)
// ...
(Although I would also prefer constraining the parameter type to array
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@duskwuff, ah, I see. Thanks.
test_is_list("mixed keys", [0 => 0, "a" => 1]); | ||
test_is_list("ordered keys", [0 => 0, 1 => 1]); | ||
test_is_list("shuffled keys", [1 => 0, 0 => 1]); | ||
test_is_list("skipped keys", [0 => 0, 2 => 2]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would also add a test to cover arrays with negative keys, e.g.: [-1 => 1, 0 => 2]
It might be useful to bring this topic to the internals mailing (internals@lists.php.net) list for discussion. |
Most likely this is going to need a small RFC, but at least an internals discussion would be good. One thing to consider would be whether this function should be Generally I do think that this is a reasonable addition, especially as we already have existing behavior (json) making this distinction, and because an internal implementation can be more efficient than any userland implementation by using the packed array information. |
I wonder if iterating over buckets in reverse would be more efficient for rejecting arrays that weren't list, here and in ext/json E.g. if you had an array with thousands of elements, but a few were unset in the middle of the array, then the key of the last bucket (that wasn't unset) wouldn't be |
Is function IMO, it's a rare use case. I've only seen it 2-3 times in 15 years and only in library/framework code. Maybe something opposite like |
The workaround/polyfill would be The value of a separate One drawback of this is that it could make it more difficult to introduce an actual |
Another approach might be to have a flag on the object representing array data to signify that it's a list. Certain operations would remove that flag: $arr = [3, 4, 5]; // $arr created with list flag
$arr[] = 7; // list flag still on
$arr[0] = 12; // list flag still on
$arr[5] = 2; // list flag removed from $arr
$a = array_merge([2, 4, 5], [1, 3, 5]); // list flag set on $a
$b = array_filter($a); // no list flag on $b I haven't ever touched PHP internals, but I'd be happy to explore this more. |
Expression |
That would mean that the way this behaves inside a function (e.g. for a parameter) depends on what the code outside the function did to the parameter before calling it, which would be unintuitive (e.g. your array_filter example). I'd be against saying something wasn't a list if it didn't have that flag.
There's small edge cases to that (e.g. if the array is infinitely recursive due to array references, this will crash), or due to NAN
A real polyfill handling all edge cases would be I can think of a few use cases for the slight performance improvement from a native
|
Since PHP has no concept of lists, not even as a pseudo-type, how do you plan to support object collections? E.g. Doctrine's Collection which implements ArrayAccess could also represent a list. Generally I think adding such functions not related to builtin types and with this generic names is a very bad idea. |
@cmb69, @nikic: What's the best way for me to start whatever process would be needed to move this forward? Just send an email to the list? @sshymko: The primary goal of this function is, as @muglug suggests, to aid in static analysis. While the behavior of this function is broadly similar to @muglug: That flag already exists -- it's referenced in my patch as @Majkl578: That's outside the scope of what this function is intended to accomplish. Consider that |
@duskwuff, yes, just write a mail to internals@ please. :) |
@duskwuff It's not out of scope, those functions you talk about test built-in types. List is not a built in type and doesn't fall into that category. |
There are already |
@TysonAndre There has never been a list in PHP though. |
True, but the concept of a list is very widespread in computer science and that type is available in most other languages. Moreover, the native PHP function takesList(array $arr) {
if ($arr) {
doSomethingWith($arr[0]);
}
} |
@muglug Yes, the same way object collections are used, but which is not supported by this PR. |
I'd argue that I do prefer the above comment by nikic that it be named |
There is a new discussion on internals about the idea of a “list” type which mean more attention on this PR again. https://externals.io/message/109760 |
I forgot about this PR, but this has been brought up again in https://externals.io/message/111744 @duskwuff - did you have any interest in creating an RFC for |
@@ -982,6 +982,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO(arginfo_is_array, _IS_BOOL, 0) | |||
ZEND_ARG_INFO(0, var) | |||
ZEND_END_ARG_INFO() | |||
|
|||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO(arginfo_is_list, _IS_BOOL, 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
php has changed to put stubs in basic_functions.stub.php - the basic_functions_arginfo.h file is automatically regenerated from this during make
@TysonAndre I'd almost forgotten about this! I don't have the time to draft an RFC personally, but I'd be delighted if someone else wanted to take that up. One extra bit of discussion material, though: |
This function tests if an array contains only sequential integer keys. While this isn't an official type, this usage is consistent with the community usage of "list" as an annotation type, cf. https://psalm.dev/docs/annotating_code/type_syntax/array_types/#lists Rebased version of php#4886 - Use .stub.php files - Add opcache constant evaluation when argument is a constant Co-Authored-By: Tyson Andre <tysonandre775@hotmail.com> Co-Authored-By: Dusk <dusk@woofle.net>
This looks to have gone stale and has a more recent PR open for the same feature #6070, therefore closing this one. |
This function tests if an array contains only sequential integer keys. While this isn't an official type, this usage is consistent with the community usage of "list" as an annotation type, cf. https://psalm.dev/docs/annotating_code/type_syntax/array_types/#lists Rebased version of php#4886 - Use .stub.php files - Add opcache constant evaluation when argument is a constant Co-Authored-By: Tyson Andre <tysonandre775@hotmail.com> Co-Authored-By: Dusk <dusk@woofle.net>
This function tests if an array contains only sequential integer keys. While this isn't an official type, this usage is consistent with the community usage of "list" as an annotation type, cf. https://psalm.dev/docs/annotating_code/type_syntax/array_types/#lists Rebased version of php#4886 - Use .stub.php files - Add opcache constant evaluation when argument is a constant Co-Authored-By: Tyson Andre <tysonandre775@hotmail.com> Co-Authored-By: Dusk <dusk@woofle.net>
This function tests if an array contains only sequential integer keys. While list isn't an official type, this usage is consistent with the community usage of "list" as an annotation type, cf. https://psalm.dev/docs/annotating_code/type_syntax/array_types/#lists Rebased and modified version of php#4886 - Use .stub.php files - Add opcache constant evaluation when argument is a constant - Change from is_list(mixed $value) to array_is_list(array $array) RFC: https://wiki.php.net/rfc/is_list Co-Authored-By: Tyson Andre <tysonandre775@hotmail.com> Co-Authored-By: Dusk <dusk@woofle.net>
This function tests if an array contains only sequential integer keys. While list isn't an official type, this usage is consistent with the community usage of "list" as an annotation type, cf. https://psalm.dev/docs/annotating_code/type_syntax/array_types/#lists Rebased and modified version of php#4886 - Use .stub.php files - Add opcache constant evaluation when argument is a constant - Change from is_list(mixed $value) to array_is_list(array $array) RFC: https://wiki.php.net/rfc/is_list Co-Authored-By: Tyson Andre <tysonandre775@hotmail.com> Co-Authored-By: Dusk <dusk@woofle.net>
This function tests if an array contains only sequential integer keys. While list isn't an official type, this usage is consistent with the community usage of "list" as an annotation type, cf. https://psalm.dev/docs/annotating_code/type_syntax/array_types/#lists Rebased and modified version of #4886 - Use .stub.php files - Add opcache constant evaluation when argument is a constant - Change from is_list(mixed $value) to array_is_list(array $array) RFC: https://wiki.php.net/rfc/is_list Co-Authored-By: Tyson Andre <tysonandre775@hotmail.com> Co-Authored-By: Dusk <dusk@woofle.net> Closes GH-6070
This function tests if an array contains only sequential integer keys. While this isn't an official type, this usage is consistent with the community usage of "list" as an annotation type, cf. https://psalm.dev/docs/annotating_code/type_syntax/array_types/#lists.
This functionality can be polyfilled, but this implementation should be much faster, as it can check for a packed array.