Skip to content

Commit 4af39b9

Browse files
Remove dot notation
1 parent cb4855d commit 4af39b9

File tree

6 files changed

+61
-219
lines changed

6 files changed

+61
-219
lines changed

ext/standard/array.c

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

6918-
/* {{{ Helper function to get a nested value from array using an array of segments */
6919-
static zval* array_get_nested_from_hash(HashTable *ht, HashTable *segments)
6918+
/* {{{ Helper function to get a nested value from array using an array of path segments */
6919+
static zval* array_get_nested(HashTable *ht, HashTable *path)
69206920
{
69216921
zval *segment_val;
69226922
zval *current;
@@ -6925,12 +6925,12 @@ static zval* array_get_nested_from_hash(HashTable *ht, HashTable *segments)
69256925
uint32_t num_segments;
69266926

69276927
current_ht = ht;
6928-
num_segments = zend_hash_num_elements(segments);
6928+
num_segments = zend_hash_num_elements(path);
69296929

6930-
/* Iterate through each segment in the array */
6930+
/* Iterate through each segment in the path array */
69316931
for (idx = 0; idx < num_segments; idx++) {
69326932
/* Get the segment at the current index */
6933-
segment_val = zend_hash_index_find(segments, idx);
6933+
segment_val = zend_hash_index_find(path, idx);
69346934

69356935
if (segment_val == NULL) {
69366936
/* Missing segment in array */
@@ -6961,160 +6961,54 @@ static zval* array_get_nested_from_hash(HashTable *ht, HashTable *segments)
69616961
current_ht = Z_ARRVAL_P(current);
69626962
}
69636963

6964-
/* Empty segments array */
6964+
/* Empty path array */
69656965
return NULL;
69666966
}
69676967
/* }}} */
69686968

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

70306977
ZEND_PARSE_PARAMETERS_START(2, 3)
70316978
Z_PARAM_ARRAY(array)
7032-
Z_PARAM_ZVAL_OR_NULL(key)
6979+
Z_PARAM_ARRAY(path)
70336980
Z_PARAM_OPTIONAL
70346981
Z_PARAM_ZVAL(default_value)
70356982
ZEND_PARSE_PARAMETERS_END();
70366983

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

7072-
default:
7073-
zend_argument_type_error(2, "must be of type string|int|array, %s given", zend_zval_value_name(key));
7074-
RETURN_THROWS();
6986+
if (result != NULL) {
6987+
RETURN_COPY_DEREF(result);
70756988
}
70766989

7077-
/* Key not found, return default value */
6990+
/* Path not found, return default value */
70786991
if (default_value != NULL) {
70796992
RETURN_COPY_DEREF(default_value);
70806993
}
70816994
}
70826995
/* }}} */
70836996

7084-
/* {{{ Checks whether a given item exists in an array using "dot" notation */
6997+
/* {{{ Checks whether a given item exists in an array using an array path */
70856998
PHP_FUNCTION(array_has)
70866999
{
70877000
zval *array;
7088-
zval *key;
7001+
zval *path;
70897002
zval *result;
7090-
HashTable *ht;
70917003

70927004
ZEND_PARSE_PARAMETERS_START(2, 2)
70937005
Z_PARAM_ARRAY(array)
7094-
Z_PARAM_ZVAL(key)
7006+
Z_PARAM_ARRAY(path)
70957007
ZEND_PARSE_PARAMETERS_END();
70967008

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

7114-
default:
7115-
zend_argument_type_error(2, "must be of type string|int|array, %s given", zend_zval_value_name(key));
7116-
RETURN_THROWS();
7117-
}
7011+
RETURN_BOOL(result != NULL);
71187012
}
71197013
/* }}} */
71207014

ext/standard/basic_functions.stub.php

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

19111911
/**
19121912
* @compile-time-eval
19131913
*/
1914-
function array_has(array $array, string|int|array $key): bool {}
1914+
function array_has(array $array, array $path): bool {}
19151915

19161916
/**
19171917
* @compile-time-eval

ext/standard/basic_functions_arginfo.h

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/standard/basic_functions_decl.h

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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)