Skip to content

Commit 2feefab

Browse files
committed
Align array_combine() function with PHP behavior
1 parent f28d67c commit 2feefab

File tree

10 files changed

+175
-15
lines changed

10 files changed

+175
-15
lines changed

src/ph7/hashmap.c

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4540,24 +4540,40 @@ static int ph7_hashmap_combine(ph7_context *pCtx,int nArg,ph7_value **apArg)
45404540
ph7_hashmap *pKey,*pValue;
45414541
ph7_value *pArray;
45424542
sxu32 n;
4543-
if( nArg < 2 ){
4544-
/* Missing arguments,return FALSE */
4545-
ph7_result_bool(pCtx,0);
4546-
return PH7_OK;
4543+
/* PHP enforces argument count and type checks. */
4544+
if( nArg != 2 ){
4545+
/* wrong number of arguments -> ArgumentCountError */
4546+
return PH7_VmThrowException(pCtx,
4547+
"ArgumentCountError",
4548+
"array_combine() expects exactly 2 arguments, %d given",
4549+
nArg
4550+
);
45474551
}
4548-
/* Make sure we are dealing with a valid hashmap */
4549-
if( !ph7_value_is_array(apArg[0]) || !ph7_value_is_array(apArg[1]) ){
4550-
/* Invalid argument,return FALSE */
4551-
ph7_result_bool(pCtx,0);
4552-
return PH7_OK;
4552+
/* Validate argument types individually so we can report the correct
4553+
* argument index in the error message. */
4554+
if( !ph7_value_is_array(apArg[0]) ){
4555+
return PH7_VmThrowException(pCtx,
4556+
"TypeError",
4557+
"array_combine(): Argument #1 ($keys) must be of type array, %s given",
4558+
ph7_type_name(apArg[0])
4559+
);
4560+
}
4561+
if( !ph7_value_is_array(apArg[1]) ){
4562+
return PH7_VmThrowException(pCtx,
4563+
"TypeError",
4564+
"array_combine(): Argument #2 ($values) must be of type array, %s given",
4565+
ph7_type_name(apArg[1])
4566+
);
45534567
}
45544568
/* Point to the internal representation of the input hashmaps */
45554569
pKey = (ph7_hashmap *)apArg[0]->x.pOther;
45564570
pValue = (ph7_hashmap *)apArg[1]->x.pOther;
45574571
if( pKey->nEntry != pValue->nEntry ){
4558-
/* Array length differs,return FALSE */
4559-
ph7_result_bool(pCtx,0);
4560-
return PH7_OK;
4572+
/* Length mismatch -> ValueError */
4573+
return PH7_VmThrowException(pCtx,
4574+
"ValueError",
4575+
"array_combine(): Argument #1 ($keys) and argument #2 ($values) must have the same number of elements"
4576+
);
45614577
}
45624578
/* Create a new array */
45634579
pArray = ph7_context_new_array(pCtx);
@@ -4569,7 +4585,24 @@ static int ph7_hashmap_combine(ph7_context *pCtx,int nArg,ph7_value **apArg)
45694585
pKe = pKey->pFirst;
45704586
pVe = pValue->pFirst;
45714587
for( n = 0 ; n < pKey->nEntry ; n++ ){
4572-
ph7_array_add_elem(pArray,HashmapExtractNodeValue(pKe),HashmapExtractNodeValue(pVe));
4588+
ph7_value *pKeyVal = HashmapExtractNodeValue(pKe);
4589+
ph7_value *pValVal = HashmapExtractNodeValue(pVe);
4590+
/* PHP treats floats used as keys in array_combine differently than
4591+
* ordinary offset access: the float is stringified rather than
4592+
* truncated. To emulate this behavior we create a temporary copy of
4593+
* the value when it is a float and convert the copy to string. The
4594+
* original array must not be mutated. */
4595+
ph7_value *pKeyCopy = pKeyVal;
4596+
if( ph7_value_is_float(pKeyVal) ){
4597+
ph7_value *pTmpKey = ph7_context_new_scalar(pCtx);
4598+
if( pTmpKey ){
4599+
PH7_MemObjStore(pKeyVal,pTmpKey);
4600+
/* Convert copy to string so it becomes "1.5" or "2" etc. */
4601+
PH7_MemObjToString(pTmpKey);
4602+
pKeyCopy = pTmpKey;
4603+
}
4604+
}
4605+
ph7_array_add_elem(pArray,pKeyCopy,pValVal);
45734606
/* Point to the next entry */
45744607
pKe = pKe->pPrev; /* Reverse link */
45754608
pVe = pVe->pPrev;

tests/ph7/001-smoke/function/array_combine/array_combine.phpt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
SPDX-FileCopyrightText: 2025 Alexandre Gomes Gaigalas <alganet@gmail.com>
33
SPDX-License-Identifier: BSD-3-Clause
44
--TEST--
5-
array_combine should build an array from keys and values, and return FALSE on mismatch
5+
array_combine should build an array from keys and values (basic)
66
--FILE--
77
<?php
88
$keys = array('a','b','c');
99
$vals = array(1,2,3);
1010
$c = array_combine($keys, $vals);
11-
echo implode(',', array_keys($c)) . PHP_EOL; // a,b,c
11+
// only check key order
12+
echo implode(',', array_keys($c)) . PHP_EOL;
1213
?>
1314
--EXPECT--
1415
a,b,c
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--CREDITS--
2+
SPDX-FileCopyrightText: 2026 Alexandre Gomes Gaigalas <alganet@gmail.com>
3+
SPDX-License-Identifier: BSD-3-Clause
4+
--TEST--
5+
array_combine with duplicate keys keeps last value for that key
6+
--FILE--
7+
<?php
8+
$keys = array('x','x','y');
9+
$vals = array(1,2,3);
10+
$c = array_combine($keys, $vals);
11+
// should map 'x' => 2 (last), 'y' => 3
12+
echo $c['x'] . ',' . $c['y'] . PHP_EOL;
13+
?>
14+
--EXPECT--
15+
2,3
16+
--CLEAN--
17+
<?php
18+
unset($keys, $vals, $c);
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
--CREDITS--
2+
SPDX-FileCopyrightText: 2026 Alexandre Gomes Gaigalas <alganet@gmail.com>
3+
SPDX-License-Identifier: BSD-3-Clause
4+
--TEST--
5+
array_combine with empty arrays returns empty
6+
--FILE--
7+
<?php
8+
$c = array_combine(array(), array());
9+
echo count($c) . PHP_EOL;
10+
?>
11+
--EXPECT--
12+
0
13+
--CLEAN--
14+
<?php
15+
unset($c);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--CREDITS--
2+
SPDX-FileCopyrightText: 2026 Alexandre Gomes Gaigalas <alganet@gmail.com>
3+
SPDX-License-Identifier: BSD-3-Clause
4+
--TEST--
5+
array_combine should keep float keys as strings
6+
--FILE--
7+
<?php
8+
$keys = array(1.5, 2.0);
9+
$vals = array('foo','bar');
10+
$c = array_combine($keys, $vals);
11+
// keys should be string representations
12+
foreach($c as $k=>$v) echo $k.":".$v."\n";
13+
?>
14+
--EXPECT--
15+
1.5:foo
16+
2:bar
17+
--CLEAN--
18+
<?php
19+
unset($keys, $vals, $c);
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--CREDITS--
2+
SPDX-FileCopyrightText: 2026 Alexandre Gomes Gaigalas <alganet@gmail.com>
3+
SPDX-License-Identifier: BSD-3-Clause
4+
--TEST--
5+
array_combine should assign correct values
6+
--FILE--
7+
<?php
8+
$keys = array('a','b','c');
9+
$vals = array(1,2,3);
10+
$c = array_combine($keys,$vals);
11+
// only check values order
12+
echo implode(',', array_values($c)) . PHP_EOL;
13+
?>
14+
--EXPECT--
15+
1,2,3
16+
--CLEAN--
17+
<?php
18+
unset($keys, $vals, $c);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--CREDITS--
2+
SPDX-FileCopyrightText: 2026 Alexandre Gomes Gaigalas <alganet@gmail.com>
3+
SPDX-License-Identifier: BSD-3-Clause
4+
--TEST--
5+
array_combine with mismatched arrays should throw ValueError
6+
--FILE--
7+
<?php
8+
array_combine(array(1), array(1,2));
9+
?>
10+
--EXPECTF--
11+
%s Fatal error: Uncaught ValueError: array_combine(): Argument #1 ($keys) and argument #2 ($values) must have the same number of elements in %s
12+
--CLEAN--
13+
<?php
14+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--CREDITS--
2+
SPDX-FileCopyrightText: 2026 Alexandre Gomes Gaigalas <alganet@gmail.com>
3+
SPDX-License-Identifier: BSD-3-Clause
4+
--TEST--
5+
array_combine with missing arguments should throw ArgumentCountError
6+
--FILE--
7+
<?php
8+
array_combine();
9+
?>
10+
--EXPECTF--
11+
%s Fatal error: Uncaught ArgumentCountError: array_combine() expects exactly 2 arguments, %d given in %s
12+
--CLEAN--
13+
<?php
14+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--CREDITS--
2+
SPDX-FileCopyrightText: 2026 Alexandre Gomes Gaigalas <alganet@gmail.com>
3+
SPDX-License-Identifier: BSD-3-Clause
4+
--TEST--
5+
array_combine with non-array keys should throw TypeError
6+
--FILE--
7+
<?php
8+
array_combine(1, array());
9+
?>
10+
--EXPECTF--
11+
%s Fatal error: Uncaught TypeError: array_combine(): Argument #1 ($keys) must be of type array, %s given in %s
12+
--CLEAN--
13+
<?php
14+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--CREDITS--
2+
SPDX-FileCopyrightText: 2026 Alexandre Gomes Gaigalas <alganet@gmail.com>
3+
SPDX-License-Identifier: BSD-3-Clause
4+
--TEST--
5+
array_combine with non-array values should throw TypeError
6+
--FILE--
7+
<?php
8+
array_combine(array(), 1);
9+
?>
10+
--EXPECTF--
11+
%s Fatal error: Uncaught TypeError: array_combine(): Argument #2 ($values) must be of type array, %s given in %s
12+
--CLEAN--
13+
<?php
14+

0 commit comments

Comments
 (0)