Skip to content

Commit 8f494a0

Browse files
Remove dot notation
1 parent 37495c1 commit 8f494a0

4 files changed

Lines changed: 52 additions & 210 deletions

File tree

ext/standard/array.c

Lines changed: 18 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -6913,8 +6913,8 @@ PHP_FUNCTION(array_key_exists)
69136913
}
69146914
/* }}} */
69156915

6916-
/* {{{ Helper function to get a nested value from array using an array of segments */
6917-
static zval* array_get_nested_from_hash(HashTable *ht, HashTable *segments)
6916+
/* {{{ Helper function to get a nested value from array using an array of path segments */
6917+
static zval* array_get_nested(HashTable *ht, HashTable *path)
69186918
{
69196919
zval *segment_val;
69206920
zval *current;
@@ -6923,12 +6923,12 @@ static zval* array_get_nested_from_hash(HashTable *ht, HashTable *segments)
69236923
uint32_t num_segments;
69246924

69256925
current_ht = ht;
6926-
num_segments = zend_hash_num_elements(segments);
6926+
num_segments = zend_hash_num_elements(path);
69276927

6928-
/* Iterate through each segment in the array */
6928+
/* Iterate through each segment in the path array */
69296929
for (idx = 0; idx < num_segments; idx++) {
69306930
/* Get the segment at the current index */
6931-
segment_val = zend_hash_index_find(segments, idx);
6931+
segment_val = zend_hash_index_find(path, idx);
69326932

69336933
if (segment_val == NULL) {
69346934
/* Missing segment in array */
@@ -6959,160 +6959,54 @@ static zval* array_get_nested_from_hash(HashTable *ht, HashTable *segments)
69596959
current_ht = Z_ARRVAL_P(current);
69606960
}
69616961

6962-
/* Empty segments array */
6962+
/* Empty path array */
69636963
return NULL;
69646964
}
69656965
/* }}} */
69666966

6967-
/* {{{ Helper function to get a nested value from array using dot notation string */
6968-
static zval* array_get_nested_from_string(HashTable *ht, const char *key, size_t key_len)
6969-
{
6970-
const char *segment_start;
6971-
const char *dot;
6972-
size_t segment_len;
6973-
size_t remaining_len;
6974-
zval *current;
6975-
HashTable *current_ht;
6976-
zend_string *segment;
6977-
6978-
current_ht = ht;
6979-
segment_start = key;
6980-
remaining_len = key_len;
6981-
6982-
/* Iterate through each dot-separated segment */
6983-
while (remaining_len > 0) {
6984-
/* Find the next dot */
6985-
dot = memchr(segment_start, '.', remaining_len);
6986-
6987-
if (dot == NULL) {
6988-
/* Last segment */
6989-
segment_len = remaining_len;
6990-
} else {
6991-
segment_len = dot - segment_start;
6992-
}
6993-
6994-
/* Look up the current segment */
6995-
segment = zend_string_init(segment_start, segment_len, 0);
6996-
current = zend_symtable_find(current_ht, segment);
6997-
zend_string_release(segment);
6998-
6999-
/* If this is the last segment, return the result */
7000-
if (dot == NULL) {
7001-
return current;
7002-
}
7003-
7004-
/* Check if the segment exists and is an array for next iteration */
7005-
if (current == NULL || Z_TYPE_P(current) != IS_ARRAY) {
7006-
return NULL;
7007-
}
7008-
7009-
/* Move to the next segment */
7010-
current_ht = Z_ARRVAL_P(current);
7011-
segment_start = dot + 1;
7012-
remaining_len = remaining_len - segment_len - 1;
7013-
}
7014-
7015-
return NULL;
7016-
}
7017-
/* }}} */
7018-
7019-
/* {{{ Retrieves a value from a deeply nested array using "dot" notation */
6967+
/* {{{ Retrieves a value from a deeply nested array using an array path */
70206968
PHP_FUNCTION(array_get)
70216969
{
70226970
zval *array;
7023-
zval *key = NULL;
6971+
zval *path;
70246972
zval *default_value = NULL;
70256973
zval *result;
7026-
HashTable *ht;
70276974

70286975
ZEND_PARSE_PARAMETERS_START(2, 3)
70296976
Z_PARAM_ARRAY(array)
7030-
Z_PARAM_ZVAL_OR_NULL(key)
6977+
Z_PARAM_ARRAY(path)
70316978
Z_PARAM_OPTIONAL
70326979
Z_PARAM_ZVAL(default_value)
70336980
ZEND_PARSE_PARAMETERS_END();
70346981

7035-
/* If key is null, return the whole array */
7036-
if (key == NULL || Z_TYPE_P(key) == IS_NULL) {
7037-
RETURN_COPY(array);
7038-
}
7039-
7040-
ht = Z_ARRVAL_P(array);
7041-
7042-
switch (Z_TYPE_P(key)) {
7043-
case IS_ARRAY:
7044-
/* Handle array keys (array of segments) */
7045-
result = array_get_nested_from_hash(ht, Z_ARRVAL_P(key));
7046-
7047-
if (result != NULL) {
7048-
RETURN_COPY_DEREF(result);
7049-
}
7050-
break;
7051-
7052-
case IS_STRING:
7053-
/* Handle string keys with dot notation */
7054-
result = array_get_nested_from_string(ht, Z_STRVAL_P(key), Z_STRLEN_P(key));
7055-
7056-
if (result != NULL) {
7057-
RETURN_COPY_DEREF(result);
7058-
}
7059-
break;
7060-
7061-
case IS_LONG:
7062-
/* Handle integer keys (simple lookup) */
7063-
result = zend_hash_index_find(ht, Z_LVAL_P(key));
7064-
7065-
if (result != NULL) {
7066-
RETURN_COPY_DEREF(result);
7067-
}
7068-
break;
6982+
result = array_get_nested(Z_ARRVAL_P(array), Z_ARRVAL_P(path));
70696983

7070-
default:
7071-
zend_argument_type_error(2, "must be of type string|int|array, %s given", zend_zval_value_name(key));
7072-
RETURN_THROWS();
6984+
if (result != NULL) {
6985+
RETURN_COPY_DEREF(result);
70736986
}
70746987

7075-
/* Key not found, return default value */
6988+
/* Path not found, return default value */
70766989
if (default_value != NULL) {
70776990
RETURN_COPY_DEREF(default_value);
70786991
}
70796992
}
70806993
/* }}} */
70816994

7082-
/* {{{ Checks whether a given item exists in an array using "dot" notation */
6995+
/* {{{ Checks whether a given item exists in an array using an array path */
70836996
PHP_FUNCTION(array_has)
70846997
{
70856998
zval *array;
7086-
zval *key;
6999+
zval *path;
70877000
zval *result;
7088-
HashTable *ht;
70897001

70907002
ZEND_PARSE_PARAMETERS_START(2, 2)
70917003
Z_PARAM_ARRAY(array)
7092-
Z_PARAM_ZVAL(key)
7004+
Z_PARAM_ARRAY(path)
70937005
ZEND_PARSE_PARAMETERS_END();
70947006

7095-
ht = Z_ARRVAL_P(array);
7096-
7097-
switch (Z_TYPE_P(key)) {
7098-
case IS_ARRAY:
7099-
/* Handle array keys (array of segments) */
7100-
result = array_get_nested_from_hash(ht, Z_ARRVAL_P(key));
7101-
RETURN_BOOL(result != NULL);
7102-
7103-
case IS_STRING:
7104-
/* Handle string keys with dot notation */
7105-
result = array_get_nested_from_string(ht, Z_STRVAL_P(key), Z_STRLEN_P(key));
7106-
RETURN_BOOL(result != NULL);
7107-
7108-
case IS_LONG:
7109-
/* Handle integer keys (simple lookup) */
7110-
RETURN_BOOL(zend_hash_index_exists(ht, Z_LVAL_P(key)));
7007+
result = array_get_nested(Z_ARRVAL_P(array), Z_ARRVAL_P(path));
71117008

7112-
default:
7113-
zend_argument_type_error(2, "must be of type string|int|array, %s given", zend_zval_value_name(key));
7114-
RETURN_THROWS();
7115-
}
7009+
RETURN_BOOL(result != NULL);
71167010
}
71177011
/* }}} */
71187012

ext/standard/basic_functions.stub.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1910,12 +1910,12 @@ function key_exists($key, array $array): bool {}
19101910
/**
19111911
* @compile-time-eval
19121912
*/
1913-
function array_get(array $array, string|int|array|null $key = null, mixed $default = null): mixed {}
1913+
function array_get(array $array, array $path, mixed $default = null): mixed {}
19141914

19151915
/**
19161916
* @compile-time-eval
19171917
*/
1918-
function array_has(array $array, string|int|array $key): bool {}
1918+
function array_has(array $array, array $path): bool {}
19191919

19201920
/**
19211921
* @compile-time-eval

ext/standard/tests/array/array_get.phpt

Lines changed: 18 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,67 +2,48 @@
22
Test array_get() function
33
--FILE--
44
<?php
5-
/*
6-
* Test functionality of array_get()
7-
*/
8-
95
echo "*** Testing array_get() ***\n";
106

11-
// Basic array access
7+
// Basic nested array access
128
$array = ['products' => ['desk' => ['price' => 100]]];
139

14-
// Test nested access with dot notation
15-
var_dump(array_get($array, 'products.desk.price'));
10+
// Test nested access with array path
11+
var_dump(array_get($array, ['products', 'desk', 'price']));
1612

17-
// Test with default value when key doesn't exist
18-
var_dump(array_get($array, 'products.desk.discount', 0));
13+
// Test with default value when path doesn't exist
14+
var_dump(array_get($array, ['products', 'desk', 'discount'], 5));
1915

20-
// Test simple key access
16+
// Test simple path with single level
2117
$simple = ['name' => 'John', 'age' => 30];
22-
var_dump(array_get($simple, 'name'));
23-
var_dump(array_get($simple, 'missing', 'default'));
24-
25-
// Test with integer key
26-
$indexed = ['a', 'b', 'c'];
27-
var_dump(array_get($indexed, 0));
28-
var_dump(array_get($indexed, 5, 'not found'));
29-
30-
// Test with null key (returns whole array)
31-
$test = ['foo' => 'bar'];
32-
var_dump(array_get($test, null));
33-
34-
// Test nested with missing intermediate key
35-
var_dump(array_get($array, 'products.chair.price', 50));
18+
var_dump(array_get($simple, ['name']));
19+
var_dump(array_get($simple, ['missing'], 'default'));
3620

3721
// Test single level key that doesn't exist
38-
var_dump(array_get($array, 'missing'));
22+
var_dump(array_get($array, ['missing']));
3923

40-
// Test with numeric string in path (like users.0.name)
24+
// Test with integer key in path
4125
$users = ['users' => [['name' => 'Alice'], ['name' => 'Bob']]];
42-
var_dump(array_get($users, 'users.0.name'));
43-
var_dump(array_get($users, 'users.1.age', 70));
44-
45-
// Test with array key (equivalent to dot notation)
46-
var_dump(array_get($array, ['products', 'desk', 'price']));
47-
var_dump(array_get($simple, ['name']));
4826
var_dump(array_get($users, ['users', 0, 'name']));
27+
var_dump(array_get($users, ['users', 1, 'name']));
28+
29+
// Test nested with missing intermediate key
4930
var_dump(array_get($array, ['products', 'chair', 'price'], 75));
5031

51-
// Test with invalid segment type in array key
32+
// Test with invalid segment type in array path
5233
var_dump(array_get($array, ['products', new stdClass(), 'price'], 'invalid'));
5334

5435
// Test with references - ensure returned value is a copy, not a reference
5536
$ref_array = ['data' => ['value' => 'original']];
5637
$ref =& $ref_array['data']['value'];
57-
$result = array_get($ref_array, 'data.value');
38+
$result = array_get($ref_array, ['data', 'value']);
5839
var_dump($result);
5940
$ref = 'modified';
6041
var_dump($result); // Should still be 'original' (not affected by reference change)
6142

6243
// Test with default value being a reference
6344
$default_value = 'default';
6445
$default_ref =& $default_value;
65-
$result_with_ref_default = array_get($ref_array, 'missing.key', $default_ref);
46+
$result_with_ref_default = array_get($ref_array, ['missing', 'key'], $default_ref);
6647
var_dump($result_with_ref_default);
6748
$default_value = 'changed';
6849
var_dump($result_with_ref_default); // Should still be 'default' (not affected by reference change)
@@ -72,22 +53,12 @@ echo "Done";
7253
--EXPECT--
7354
*** Testing array_get() ***
7455
int(100)
75-
int(0)
56+
int(5)
7657
string(4) "John"
7758
string(7) "default"
78-
string(1) "a"
79-
string(9) "not found"
80-
array(1) {
81-
["foo"]=>
82-
string(3) "bar"
83-
}
84-
int(50)
8559
NULL
8660
string(5) "Alice"
87-
int(70)
88-
int(100)
89-
string(4) "John"
90-
string(5) "Alice"
61+
string(3) "Bob"
9162
int(75)
9263
string(7) "invalid"
9364
string(8) "original"

0 commit comments

Comments
 (0)