Skip to content

Commit 73ab7b3

Browse files
committed
Allow array_diff() and array_intersect() with single array argument
Both of these functions are well-defined when used with a single array argument -- rejecting this case was an artificial limitation. This is not useful when called with explicit arguments, but removes edge-cases when used with argument unpacking: // OK even if $excludes is empty. array_diff($array, ...$excludes); // OK even if $arrays contains a single array only. array_intersect(...$arrays); This matches the behavior of functions like array_merge() and array_push(), which also allow calls with no array or a single array respectively. Closes GH-6097.
1 parent 9975986 commit 73ab7b3

File tree

46 files changed

+1251
-1460
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1251
-1460
lines changed

UPGRADING

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,14 @@ PHP 8.0 UPGRADE NOTES
771771
. Sorting functions are now stable, which means that equal-comparing elements
772772
will retain their original order.
773773
RFC: https://wiki.php.net/rfc/stable_sorting
774+
. array_diff(), array_intersect() and their variations can now be used with
775+
a single array as argument. This means that usages like the following are
776+
now possible:
777+
778+
// OK even if $excludes is empty.
779+
array_diff($array, ...$excludes);
780+
// OK even if $arrays only contains a single array.
781+
array_intersect(...$arrays);
774782

775783
- Zip:
776784
. Extension updated to version 1.19.0

Zend/tests/function_arguments/argument_count_incorrect_internal_strict.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ try {
1111
}
1212

1313
try {
14-
array_diff([]);
14+
array_diff();
1515
} catch (ArgumentCountError $e) {
1616
echo get_class($e) . PHP_EOL;
1717
echo $e->getMessage(), "\n";
@@ -21,4 +21,4 @@ try {
2121
ArgumentCountError
2222
substr() expects at least 2 arguments, 1 given
2323
ArgumentCountError
24-
At least 2 arguments are required, 1 given
24+
array_diff() expects at least 1 argument, 0 given

ext/standard/array.c

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4613,7 +4613,6 @@ static void php_array_intersect_key(INTERNAL_FUNCTION_PARAMETERS, int data_compa
46134613
int (*intersect_data_compare_func)(zval *, zval *) = NULL;
46144614
zend_bool ok;
46154615
zval *val, *data;
4616-
int req_args;
46174616
char *param_spec;
46184617
zend_string *key;
46194618
zend_ulong h;
@@ -4622,25 +4621,18 @@ static void php_array_intersect_key(INTERNAL_FUNCTION_PARAMETERS, int data_compa
46224621
argc = ZEND_NUM_ARGS();
46234622
if (data_compare_type == INTERSECT_COMP_DATA_USER) {
46244623
/* INTERSECT_COMP_DATA_USER - array_uintersect_assoc() */
4625-
req_args = 3;
46264624
param_spec = "+f";
46274625
intersect_data_compare_func = zval_user_compare;
46284626
} else {
46294627
/* INTERSECT_COMP_DATA_NONE - array_intersect_key()
46304628
INTERSECT_COMP_DATA_INTERNAL - array_intersect_assoc() */
4631-
req_args = 2;
46324629
param_spec = "+";
46334630

46344631
if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL) {
46354632
intersect_data_compare_func = zval_compare;
46364633
}
46374634
}
46384635

4639-
if (argc < req_args) {
4640-
zend_argument_count_error("At least %d arguments are required, %d given", req_args, argc);
4641-
RETURN_THROWS();
4642-
}
4643-
46444636
if (zend_parse_parameters(ZEND_NUM_ARGS(), param_spec, &args, &argc, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
46454637
RETURN_THROWS();
46464638
}
@@ -4701,7 +4693,6 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int
47014693
int arr_argc, i, c = 0;
47024694
uint32_t idx;
47034695
Bucket **lists, *list, **ptrs, *p;
4704-
uint32_t req_args;
47054696
char *param_spec;
47064697
zend_fcall_info fci1, fci2;
47074698
zend_fcall_info_cache fci1_cache = empty_fcall_info_cache, fci2_cache = empty_fcall_info_cache;
@@ -4717,24 +4708,17 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int
47174708

47184709
if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL) {
47194710
/* array_intersect() */
4720-
req_args = 2;
47214711
param_spec = "+";
47224712
intersect_data_compare_func = php_array_data_compare_string_unstable;
47234713
} else if (data_compare_type == INTERSECT_COMP_DATA_USER) {
47244714
/* array_uintersect() */
4725-
req_args = 3;
47264715
param_spec = "+f";
47274716
intersect_data_compare_func = php_array_user_compare_unstable;
47284717
} else {
47294718
ZEND_ASSERT(0 && "Invalid data_compare_type");
47304719
return;
47314720
}
47324721

4733-
if (ZEND_NUM_ARGS() < req_args) {
4734-
zend_argument_count_error("At least %d arguments are required, %d given", req_args, ZEND_NUM_ARGS());
4735-
RETURN_THROWS();
4736-
}
4737-
47384722
if (zend_parse_parameters(ZEND_NUM_ARGS(), param_spec, &args, &arr_argc, &fci1, &fci1_cache) == FAILURE) {
47394723
RETURN_THROWS();
47404724
}
@@ -4747,29 +4731,25 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int
47474731

47484732
if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL && key_compare_type == INTERSECT_COMP_KEY_INTERNAL) {
47494733
/* array_intersect_assoc() or array_intersect_key() */
4750-
req_args = 2;
47514734
param_spec = "+";
47524735
intersect_key_compare_func = php_array_key_compare_string_unstable;
47534736
intersect_data_compare_func = php_array_data_compare_string_unstable;
47544737
} else if (data_compare_type == INTERSECT_COMP_DATA_USER && key_compare_type == INTERSECT_COMP_KEY_INTERNAL) {
47554738
/* array_uintersect_assoc() */
4756-
req_args = 3;
47574739
param_spec = "+f";
47584740
intersect_key_compare_func = php_array_key_compare_string_unstable;
47594741
intersect_data_compare_func = php_array_user_compare_unstable;
47604742
fci_data = &fci1;
47614743
fci_data_cache = &fci1_cache;
47624744
} else if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL && key_compare_type == INTERSECT_COMP_KEY_USER) {
47634745
/* array_intersect_uassoc() or array_intersect_ukey() */
4764-
req_args = 3;
47654746
param_spec = "+f";
47664747
intersect_key_compare_func = php_array_user_key_compare_unstable;
47674748
intersect_data_compare_func = php_array_data_compare_string_unstable;
47684749
fci_key = &fci1;
47694750
fci_key_cache = &fci1_cache;
47704751
} else if (data_compare_type == INTERSECT_COMP_DATA_USER && key_compare_type == INTERSECT_COMP_KEY_USER) {
47714752
/* array_uintersect_uassoc() */
4772-
req_args = 4;
47734753
param_spec = "+ff";
47744754
intersect_key_compare_func = php_array_user_key_compare_unstable;
47754755
intersect_data_compare_func = php_array_user_compare_unstable;
@@ -4782,11 +4762,6 @@ static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int
47824762
return;
47834763
}
47844764

4785-
if (ZEND_NUM_ARGS() < req_args) {
4786-
zend_argument_count_error("At least %d arguments are required, %d given", req_args, ZEND_NUM_ARGS());
4787-
RETURN_THROWS();
4788-
}
4789-
47904765
if (zend_parse_parameters(ZEND_NUM_ARGS(), param_spec, &args, &arr_argc, &fci1, &fci1_cache, &fci2, &fci2_cache) == FAILURE) {
47914766
RETURN_THROWS();
47924767
}
@@ -5023,19 +4998,11 @@ static void php_array_diff_key(INTERNAL_FUNCTION_PARAMETERS, int data_compare_ty
50234998
/* Get the argument count */
50244999
argc = ZEND_NUM_ARGS();
50255000
if (data_compare_type == DIFF_COMP_DATA_USER) {
5026-
if (argc < 3) {
5027-
zend_argument_count_error("At least 3 arguments are required, %d given", ZEND_NUM_ARGS());
5028-
RETURN_THROWS();
5029-
}
50305001
if (zend_parse_parameters(ZEND_NUM_ARGS(), "+f", &args, &argc, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
50315002
RETURN_THROWS();
50325003
}
50335004
diff_data_compare_func = zval_user_compare;
50345005
} else {
5035-
if (argc < 2) {
5036-
zend_argument_count_error("At least 2 arguments are required, %d given", ZEND_NUM_ARGS());
5037-
RETURN_THROWS();
5038-
}
50395006
if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
50405007
RETURN_THROWS();
50415008
}
@@ -5100,7 +5067,6 @@ static void php_array_diff(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_
51005067
int arr_argc, i, c;
51015068
uint32_t idx;
51025069
Bucket **lists, *list, **ptrs, *p;
5103-
uint32_t req_args;
51045070
char *param_spec;
51055071
zend_fcall_info fci1, fci2;
51065072
zend_fcall_info_cache fci1_cache = empty_fcall_info_cache, fci2_cache = empty_fcall_info_cache;
@@ -5116,24 +5082,17 @@ static void php_array_diff(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_
51165082

51175083
if (data_compare_type == DIFF_COMP_DATA_INTERNAL) {
51185084
/* array_diff */
5119-
req_args = 2;
51205085
param_spec = "+";
51215086
diff_data_compare_func = php_array_data_compare_string_unstable;
51225087
} else if (data_compare_type == DIFF_COMP_DATA_USER) {
51235088
/* array_udiff */
5124-
req_args = 3;
51255089
param_spec = "+f";
51265090
diff_data_compare_func = php_array_user_compare_unstable;
51275091
} else {
51285092
ZEND_ASSERT(0 && "Invalid data_compare_type");
51295093
return;
51305094
}
51315095

5132-
if (ZEND_NUM_ARGS() < req_args) {
5133-
zend_argument_count_error("At least %d arguments are required, %d given", req_args, ZEND_NUM_ARGS());
5134-
RETURN_THROWS();
5135-
}
5136-
51375096
if (zend_parse_parameters(ZEND_NUM_ARGS(), param_spec, &args, &arr_argc, &fci1, &fci1_cache) == FAILURE) {
51385097
RETURN_THROWS();
51395098
}
@@ -5146,29 +5105,25 @@ static void php_array_diff(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_
51465105

51475106
if (data_compare_type == DIFF_COMP_DATA_INTERNAL && key_compare_type == DIFF_COMP_KEY_INTERNAL) {
51485107
/* array_diff_assoc() or array_diff_key() */
5149-
req_args = 2;
51505108
param_spec = "+";
51515109
diff_key_compare_func = php_array_key_compare_string_unstable;
51525110
diff_data_compare_func = php_array_data_compare_string_unstable;
51535111
} else if (data_compare_type == DIFF_COMP_DATA_USER && key_compare_type == DIFF_COMP_KEY_INTERNAL) {
51545112
/* array_udiff_assoc() */
5155-
req_args = 3;
51565113
param_spec = "+f";
51575114
diff_key_compare_func = php_array_key_compare_string_unstable;
51585115
diff_data_compare_func = php_array_user_compare_unstable;
51595116
fci_data = &fci1;
51605117
fci_data_cache = &fci1_cache;
51615118
} else if (data_compare_type == DIFF_COMP_DATA_INTERNAL && key_compare_type == DIFF_COMP_KEY_USER) {
51625119
/* array_diff_uassoc() or array_diff_ukey() */
5163-
req_args = 3;
51645120
param_spec = "+f";
51655121
diff_key_compare_func = php_array_user_key_compare_unstable;
51665122
diff_data_compare_func = php_array_data_compare_string_unstable;
51675123
fci_key = &fci1;
51685124
fci_key_cache = &fci1_cache;
51695125
} else if (data_compare_type == DIFF_COMP_DATA_USER && key_compare_type == DIFF_COMP_KEY_USER) {
51705126
/* array_udiff_uassoc() */
5171-
req_args = 4;
51725127
param_spec = "+ff";
51735128
diff_key_compare_func = php_array_user_key_compare_unstable;
51745129
diff_data_compare_func = php_array_user_compare_unstable;
@@ -5181,11 +5136,6 @@ static void php_array_diff(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_
51815136
return;
51825137
}
51835138

5184-
if (ZEND_NUM_ARGS() < req_args) {
5185-
zend_argument_count_error("At least %d arguments are required, %d given", req_args, ZEND_NUM_ARGS());
5186-
RETURN_THROWS();
5187-
}
5188-
51895139
if (zend_parse_parameters(ZEND_NUM_ARGS(), param_spec, &args, &arr_argc, &fci1, &fci1_cache, &fci2, &fci2_cache) == FAILURE) {
51905140
RETURN_THROWS();
51915141
}
@@ -5377,11 +5327,6 @@ PHP_FUNCTION(array_diff)
53775327
zend_long idx;
53785328
zval dummy;
53795329

5380-
if (ZEND_NUM_ARGS() < 2) {
5381-
zend_argument_count_error("At least 2 arguments are required, %d given", ZEND_NUM_ARGS());
5382-
RETURN_THROWS();
5383-
}
5384-
53855330
ZEND_PARSE_PARAMETERS_START(1, -1)
53865331
Z_PARAM_VARIADIC('+', args, argc)
53875332
ZEND_PARSE_PARAMETERS_END();

ext/standard/basic_functions.stub.php

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -178,47 +178,47 @@ function array_change_key_case(array $array, int $case = CASE_LOWER): array {}
178178

179179
function array_unique(array $array, int $flags = SORT_STRING): array {}
180180

181-
function array_intersect_key(array $array1, array $array2, array ...$arrays): array {}
181+
function array_intersect_key(array $array, array ...$arrays): array {}
182182

183183
/** @param array|callable $rest */
184-
function array_intersect_ukey(array $array1, array $array2, ...$rest): array {}
184+
function array_intersect_ukey(array $array, ...$rest): array {}
185185

186-
function array_intersect(array $array1, array $array2, array ...$arrays): array {}
186+
function array_intersect(array $array, array ...$arrays): array {}
187187

188188
/** @param array|callable $rest */
189-
function array_uintersect(array $array1, array $array2, ...$rest): array {}
189+
function array_uintersect(array $array, ...$rest): array {}
190190

191-
function array_intersect_assoc(array $array1, array $array2, array ...$arrays): array {}
191+
function array_intersect_assoc(array $array, array ...$arrays): array {}
192192

193193
/** @param array|callable $rest */
194-
function array_uintersect_assoc(array $array1, array $array2, ...$rest): array {}
194+
function array_uintersect_assoc(array $array, ...$rest): array {}
195195

196196
/** @param array|callable $rest */
197-
function array_intersect_uassoc(array $array1, array $array2, ...$rest): array {}
197+
function array_intersect_uassoc(array $array, ...$rest): array {}
198198

199199
/** @param array|callable $rest */
200-
function array_uintersect_uassoc(array $array1, array $array2, ...$rest): array {}
200+
function array_uintersect_uassoc(array $array, ...$rest): array {}
201201

202-
function array_diff_key(array $array1, array $array2, array ...$arrays): array {}
202+
function array_diff_key(array $array, array ...$arrays): array {}
203203

204204
/** @param array|callable $rest */
205-
function array_diff_ukey(array $array1, array $array2, ...$rest): array {}
205+
function array_diff_ukey(array $array, ...$rest): array {}
206206

207-
function array_diff(array $array1, array $array2, array ...$arrays): array {}
207+
function array_diff(array $array, array ...$arrays): array {}
208208

209209
/** @param array|callable $rest */
210-
function array_udiff(array $array1, array $array2, ...$rest): array {}
210+
function array_udiff(array $array, ...$rest): array {}
211211

212-
function array_diff_assoc(array $array1, array $array2, array ...$arrays): array {}
212+
function array_diff_assoc(array $array, array ...$arrays): array {}
213213

214214
/** @param array|callable $rest */
215-
function array_diff_uassoc(array $array1, array $array2, ...$rest): array {}
215+
function array_diff_uassoc(array $array, ...$rest): array {}
216216

217217
/** @param array|callable $rest */
218-
function array_udiff_assoc(array $array1, array $array2, ...$rest): array {}
218+
function array_udiff_assoc(array $array, ...$rest): array {}
219219

220220
/** @param array|callable $rest */
221-
function array_udiff_uassoc(array $array1, array $array2, ...$rest): array {}
221+
function array_udiff_uassoc(array $array, ...$rest): array {}
222222

223223
/**
224224
* @param array $array1

ext/standard/basic_functions_arginfo.h

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: 1d2a7229aa506c8da54ecbed6480836aa14fd484 */
2+
* Stub hash: 56f49d359d2b11383a3f1401d0a3730192c28fc0 */
33

44
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0)
55
ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0)
@@ -273,15 +273,13 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_array_unique, 0, 1, IS_ARRAY, 0)
273273
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "SORT_STRING")
274274
ZEND_END_ARG_INFO()
275275

276-
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_array_intersect_key, 0, 2, IS_ARRAY, 0)
277-
ZEND_ARG_TYPE_INFO(0, array1, IS_ARRAY, 0)
278-
ZEND_ARG_TYPE_INFO(0, array2, IS_ARRAY, 0)
276+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_array_intersect_key, 0, 1, IS_ARRAY, 0)
277+
ZEND_ARG_TYPE_INFO(0, array, IS_ARRAY, 0)
279278
ZEND_ARG_VARIADIC_TYPE_INFO(0, arrays, IS_ARRAY, 0)
280279
ZEND_END_ARG_INFO()
281280

282-
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_array_intersect_ukey, 0, 2, IS_ARRAY, 0)
283-
ZEND_ARG_TYPE_INFO(0, array1, IS_ARRAY, 0)
284-
ZEND_ARG_TYPE_INFO(0, array2, IS_ARRAY, 0)
281+
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_array_intersect_ukey, 0, 1, IS_ARRAY, 0)
282+
ZEND_ARG_TYPE_INFO(0, array, IS_ARRAY, 0)
285283
ZEND_ARG_VARIADIC_INFO(0, rest)
286284
ZEND_END_ARG_INFO()
287285

ext/standard/tests/array/array_diff_1.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ try {
1515
echo "OK!";
1616
?>
1717
--EXPECT--
18-
array_diff(): Argument #2 ($array2) must be of type array, int given
18+
array_diff(): Argument #2 must be of type array, int given
1919
OK!

ext/standard/tests/array/array_diff_assoc_error.phpt

Lines changed: 0 additions & 38 deletions
This file was deleted.

0 commit comments

Comments
 (0)