The project is developed using PHP language, which uses MONGO DB storage; the data in MONGO DB is strongly typed, and the data in PHP is weakly typed. Last Friday, I couldn't find a data query in MONGODB. Finally, I found that the problem is The numeric string subscript of the PHP array is automatically converted into an integer subscript; therefore, although PHP is a weakly typed language, we must also pay attention to the current type of the variable and be familiar with PHP's automatic type conversion rules. In some type-sensitive places, Perform type judgment or forced type conversion.
The following example program simply explains this phenomenon:
Php code
$id = "22";
$arr1[$id] = "xxx";
var_dump($arr1);
$id = 22;
$arr2[$id] = "xxx";
var_dump($arr2);
$id = "022";
$arr3[$id] = "xxx";
var_dump($arr3);
$id = "2222222222222";
$arr4[$id] = "xxx";
var_dump($arr4);
$id = "22";$arr1[$id] = "xxx";var_dump($arr1);$id = 22;$arr2[$id] = "xxx";var_dump($arr2);$id = " 022";$arr3[$id] = "xxx";var_dump($arr3);$id = "2222222222222";$arr4[$id] = "xxx";var_dump($arr4);
The output of this program is:
Php code
array(1) {
[22]=>
string(3) "xxx"
}
array(1) {
[22]=>
string(3) "xxx"
}
array(1) {
["022"]=>
string(3) "xxx"
}
array(1) {
["2222222222222"]=>
string(3) "xxx"
}
array(1) { [22]=> string(3) "xxx"}array(1) { [22]=> string(3) "xxx"}array(1) { ["022"]=> ; string(3) "xxx"}array(1) { ["2222222222222"]=> string(3) "xxx"}
So, how is PHP’s array string subscript type determined? Let's take a look at the source code of PHP.
First, we search [ in Zend/zend_language_parser.y to find the semantic parsing rules of the array:
Php code
object_dim_list:
object_dim_list '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); }
| object_dim_list '{' expr '}' { fetch_string_offset(&$$, &$1, &$3 TSRMLS_CC); }
| variable_name { znode tmp_znode; zend_do_pop_object(&tmp_znode TSRMLS_CC); zend_do_fetch_property(&$$, &tmp_znode, &$1 TSRMLS_CC);}
;
object_dim_list: object_dim_list '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } object_dim_list '{' expr '}' { fetch_string_offset( &$$, &$1, &$3 TSRMLS_CC); } | variable_name { znode tmp_znode; zend_do_pop_object(&tmp_znode TSRMLS_CC); zend_do_fetch_property(&$$, &tmp_znode, &$1 TSRMLS_CC);} ;
We are using an array, so we use the first rule fetch_array_dim. In the fetch_array_dim function, we find that the generated opcode is ZEND_FETCH_DIM_W(84). In Zend/zend_vm_def.h, zend_fetch_dimension_address handles the descriptor logic in the processing function of ZEND_FETCH_DIM_W.
Continue to track, from zend_fetch_dimension_address function to zend_fetch_dimension_address_inner, and then to zend_symtable_update:
Php code
static inline int zend_symtable_update(HashTable *ht, char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest)
{
HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_update(ht, idx, pData, nDataSize, pDest));
Return zend_hash_update(ht, arKey, nKeyLength, pData, nDataSize, pDest);
}
static inline int zend_symtable_update(HashTable *ht, char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest) HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_update(ht, idx, pData, nDataSize, pDest) ); return zend_hash_update(ht, arKey, nKeyLength, pData, nDataSize, pDest);
The HANDLE_NUMERIC macro is very interesting. If the string subscript arKey can be converted into a long integer idx, then call zend_hash_index_update to insert the data into the idx position, otherwise call zend_hash_update to modify the value of the arKey position. Let’s take a look at the specific definition of macro:
Php code
#define HANDLE_NUMERIC(key, length, func) {
register char *tmp=key;
if (*tmp=='-') {
tmp++; tmp++;
If ((*tmp>='0' && *tmp<='9')) do { /* possibly a numeric index */ char *end=key+length-1;
long idx;
if (*tmp++=='0' && length>2) { /* don't accept numbers with leading zeros */
break;
}
while (tmp
break;
}
tmp++;
}
if (tmp==end && *tmp==' ') { /* a numeric index */
if (*key=='-') {
idx = strtol(key, NULL, 10);
if (idx!=LONG_MIN) {
return func;
}
} else {
idx = strtol(key, NULL, 10);
if (idx!=LONG_MAX) {
return func;
}
}
}
} while (0);
}
#define HANDLE_NUMERIC(key, length, func) { register char *tmp=key; if (*tmp=='-') { tmp++; } if ((*tmp>='0' && *tmp<='9')) do { /* possibly a numeric index */ char *end=key+length-1; long idx; if (*tmp++=='0' && length>2) { /* don't accept numbers with leading zeros */ break; } while (tmp