search
HomeBackend DevelopmentPHP Tutorial PHP数组上标类型陷阱

PHP数组下标类型陷阱

???? 项目使用PHP语言开发,其中用到了MONGO DB存储;MONGO DB里的数据是强类型,PHP里的数据是弱类型,上周五我在MONGODB里查询一个数据总是找不到,最后发现问题是PHP数组的数值型字符串下标自动转变成了整数型下标;因此虽然PHP是弱类型语言,我们也要关注变量当前什么类型,熟悉PHP的类型自动转换规则,在一些类型敏感的地方要进行类型判断或者强制类型转换。

??? 以下示例程序简单解释了这个现象:

?

$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);

??? 这段程序的输出是:

?

array(1) {
  [22]=>
  string(3) "xxx"
}
array(1) {
  [22]=>
  string(3) "xxx"
}
array(1) {
  ["022"]=>
  string(3) "xxx"
}
array(1) {
  ["2222222222222"]=>
  string(3) "xxx"
}
?

??? 那么,PHP的数组字符串下标类型是怎么确定的呢?我们一起到PHP的源代码里看一看。

??? 首先,我们在Zend/zend_language_parser.y里搜索[,找到数组的语义解析规则:

?

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);}   
;

?

?? 我们使用的是数组,因此使用第一个规则fetch_array_dim,在fetch_array_dim函数里,我们发现生成的opcode是ZEND_FETCH_DIM_W(84)。在Zend/zend_vm_def.h里,ZEND_FETCH_DIM_W的处理函数里zend_fetch_dimension_address处理取下标逻辑。

?

??? 继续跟踪下去,从zend_fetch_dimension_address函数到zend_fetch_dimension_address_inner,再到zend_symtable_update:

?

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);                                      
} 

?

?? HANDLE_NUMERIC这个宏很有意思,如果字符串下标arKey可转化为长整数idx,则调用zend_hash_index_update把数据插入到idx位置,否则调用zend_hash_update修改arKey位置的值 。我们看下宏的具体定义:

?

#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<end) {                                                               \
            if (!(*tmp>='0' && *tmp<='9')) {                                            \
                break;                                                                  \
            }                                                                           \
            tmp++;                                                                      \
        }                                                                               \
        if (tmp==end && *tmp=='\0') { /* 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);                                                                        \
}

??? 从宏里我们知道了字符串下标自动转化为长整数下标的规则:

??? 1. 全部为数字,但是不能有前导0,比如arKey="0123"不会转化成123

??? 2. 不能超过long的表示范围(LONG_MIN, LONG_MAX),即(-2147483648, 2147483647)

?

?

?

?

?

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
/tmp/文件夹在Linux系统中的清理原理及tmp文件的作用/tmp/文件夹在Linux系统中的清理原理及tmp文件的作用Dec 21, 2023 pm 05:36 PM

.tmp文件大部分都是因为不正常关机、或死机后所留下的文件,这些临时的暂存盘,在你重新开机后,已经没有任何的用途,可以放心删除。大家在使用Windows操作系统的时候,可能会经常在C盘根目录发现一些后缀名为TMP的文件,还会在Windows目录里发现一个TEMP的目录,TMP文件是各种软件或系统产生的临时文件,也就是常说的垃圾文件。Windows产生的临时文件,本质上和虚拟内存没什么两样,只不过临时文件比虚拟内存更具有针对性,单独为某个程序服务而已。而它的专一性导致了许多新手对他望而生畏,不删占

在Vue应用中使用axios时出现“TypeError: Failed to fetch”怎么办?在Vue应用中使用axios时出现“TypeError: Failed to fetch”怎么办?Jun 24, 2023 pm 11:03 PM

最近,在使用Vue应用开发过程中,我遇到了一个常见的问题:“TypeError:Failedtofetch”错误提示。这个问题出现在使用axios进行HTTP请求时,后端服务器没有正确响应请求时发生。这种错误提示通常表明请求无法到达服务器,可能是由于网络原因或服务器未响应造成的。出现这个错误提示后,我们应该怎么办呢?以下是一些解决方法:检查网络连接由于

linux中tmp什么意思linux中tmp什么意思Mar 10, 2023 am 09:26 AM

linux中tmp指的是一个存储临时文件的文件夹,该文件夹包含系统和用户创建的临时文件;tmp文件夹的默认时限是30天,30天不访问的tmp下的文件会被系统自动删除的。

如何在CentOS 7中访问并清理/tmp目录中的垃圾文件?如何在CentOS 7中访问并清理/tmp目录中的垃圾文件?Dec 27, 2023 pm 09:10 PM

centos7系统中tmp目录下有很多垃圾,想要清除垃圾,该怎么清除呢?下面我们就来看看详细的教程。查看tmp文件目录下文件列表,执行命令cdtmp/切换到tmp当前文件目录,执行ll命令,查看当前目录下文件列表。如下图所示。使用rm删除文件命令,需要注意的是rm命令是将文件永远从系统中删除,因此建议在使用rm命令时,最好是在删除文件前给出提示。使用命令rm-i文件名,等用户确认删除(y)或跳过删除(n),系统进行相应的操作。如下图所示。

TmP是什么文件?TmP是什么文件?Dec 25, 2023 pm 03:39 PM

“tmp”文件是临时文件,通常由操作系统或程序在运行过程中产生,用于存储临时数据或程序运行时的中间结果。这些文件主要用于帮助程序顺利执行,但它们在程序执行完毕后通常会被自动删除。tmp文件通常可以在Windows系统的C盘根目录下找到。然而,tmp文件与特定应用程序或系统有关,因此它们的具体内容和用途可能因应用程序而异。

使用C#中的Array.Sort函数对数组进行排序使用C#中的Array.Sort函数对数组进行排序Nov 18, 2023 am 10:37 AM

标题:C#中使用Array.Sort函数对数组进行排序的示例正文:在C#中,数组是一种常用的数据结构,经常需要对数组进行排序操作。C#提供了Array类,其中有Sort方法可以方便地对数组进行排序。本文将演示如何使用C#中的Array.Sort函数对数组进行排序,并提供具体的代码示例。首先,我们需要了解一下Array.Sort函数的基本用法。Array.So

tmp是什么文件tmp是什么文件Feb 22, 2023 pm 02:35 PM

tmp是各种软件或系统产生的临时文件,也就是常说的垃圾文件。通常,创建临时文件的程序会在完成时将其删除,但有时候这些文件会被保留。临时文件被保留的原因可能有多种:程序可能在完成安装前被中断,或在重新启动时崩溃;对于这些文件,一般没有什么使用价值,我们可以直接将其删除。

如何在Zend框架中使用ACL(Access Control List)进行权限控制如何在Zend框架中使用ACL(Access Control List)进行权限控制Jul 29, 2023 am 09:24 AM

如何在Zend框架中使用ACL(AccessControlList)进行权限控制导言:在一个Web应用程序中,权限控制是至关重要的一项功能。它可以确保用户只能访问其有权访问的页面和功能,并防止未经授权的访问。Zend框架提供了一种方便的方法来实现权限控制,即使用ACL(AccessControlList)组件。本文将介绍如何在Zend框架中使用ACL

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
2 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
Repo: How To Revive Teammates
1 months agoBy尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: How To Get Giant Seeds
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

EditPlus Chinese cracked version

EditPlus Chinese cracked version

Small size, syntax highlighting, does not support code prompt function

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser is a secure browser environment for taking online exams securely. This software turns any computer into a secure workstation. It controls access to any utility and prevents students from using unauthorized resources.

MantisBT

MantisBT

Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

SublimeText3 English version

SublimeText3 English version

Recommended: Win version, supports code prompts!

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)