PHP弱类型实现原理

$a = 123;
$b = '456';

var_dump($a); // int(123)
var_dump($b); // string(3) "456"

甲小蛙:同学们,今天我们分享的内容是:PHP弱类型的实现原理,上边的代码我们已经写过无数次,不知道你有没有疑问,输出的时候它是怎么知道 $a 是纯数字,而 $b 是字符串的 ?

甲小蛙:这就是 PHP 的弱类型特性,那么这个弱类型是怎么实现的呢,首先我们来看 PHP变量 的底层实现

typedef struct _zval_struct zval;
...
struct _zval_struct {
    zvalue_value value; /* 储存变量的值 */
    zend_uint refcount__gc; /* 引用计数,用于GC */
    zend_uchar type; /* 储存变量类型 */
    zend_uchar is_ref__gc; /* 是否为引用,即 &$a */
};

甲小雷:对不起老师,打断一下,这是什么语言,我们好像在哪儿见过~你记得吗 ?

甲小蛙:是的,你们见过,这就是大名鼎鼎的 C 语言,PHP就是用C语言实现的,每个成功的语言背后总有一个默默无闻的语言~

甲小雷:老师,我明白了,type 记录了这个变量的类型,而 zvalue_value 这个东东才真正存储了变量的值

甲小蛙:回答非常正确,但是问题又来了,我们知道C语言可是强类型的,123 和 '456' 在 zvalue_value 中又是怎么存储的呢 ?

甲小雷:这...

甲小浩:Talk is cheap,show me the code

typedef union _zvalue_value {
    long lval; /* 长整型 */
    double dval; /* 浮点型 */
    struct {
        char *val;
        int len; /* 字符串的长度 */
    } str; /* 字符串 */
    HashTable *ht; /* 哈希 */
    zend_object_value obj; /* 对象 */
} zvalue_value;

甲小雷:这又是个什么鬼 ?

甲小蛙:这是 C语言 中的一种数据类型 - 共同体:允许你在相同的内存地址存储不同的数据类型,你可以定义很多种数据类型,但是任何时候都只能有一个成员带有值。

甲小雷:恍然大雾,终于明白 PHP的弱类型是怎么实现的了,妙,实在是妙。可是,我发现里边没有存在 bool 类型的成员,也没有存放 array 的成员,怎么回事 ?

甲小蛙:很好的问题,因为 bool 值只有 true 和 false,也可以理解为 1 和 0,那么 long 也可以用来存储 bool 的值了;另外,PHP的数组存放在 HashTable 中,具体怎么实现的可以查下资料

甲小蛙:顺便再补充一点点内容,很多同学在写代码的时候,会这样写

$a = 'abcdefg';
$alen = strlen($a);
for ($i = 0; $i < $alen; $i++) {
    // do something
}

$b = [1, 2, 3, 4, 5, 6];
$bsize = count($b);
for ($j = 0; $j < $bsize; $j++) {
    // do something
}

甲小蛙:担心频繁地调用 strlen 和 count 方法会影响程序性能,因为每次都去计算他们的长度......但其实效果恰恰相反,看了PHP的变量实现后,我们知道调用 strlen 和 count 的时候只是获取了对应的 len 和 hashtable 中的 size 值而已,并没有去重新计算长度和大小(这在很多高级语言都是类似实现),我们新创建一个变量用来存储 len 和 size 反而需要开辟新的空间来存储他们,浪费内存,得不偿失

甲小蛙:顺带再补充一点点内容,共同体为了能放下最大的成员,即:zend_object_value,共同体在64位系统中占用24个字节空间,zend_object_value 占用 16个字节,而如果存放一个 bool 值,仍然会开辟很大的内存,这儿的实现在 PHP7 中得到了优化,改用指针的方式不直接存储对象本身,这样就把共同体的占用空间减小了,这也是 PHP7 会变快的一个重要原因。

甲小蛙:今天的分享到此结束!See you~

发布了3 篇原创文章 · 获赞 3 · 访问量 135

猜你喜欢

转载自blog.csdn.net/epwqgdnbrh/article/details/104749714