首頁 後端開發 php教程 PHP内核探索:变量存储与类型使用说明_PHP教程

PHP内核探索:变量存储与类型使用说明_PHP教程

Jul 13, 2016 am 10:39 AM
變數儲存 類型

先回答前面一节的那个问题吧。

复制代码 代码如下:

    $foo = 10;
    $bar = 20;

    function change() {
        global $foo;
        //echo '函数内部$foo = '.$foo.'
';
        //如果不把$bar定义为global变量,函数体内是不能访问$bar的
        $bar = 0;
        $foo++;
    }

    change();
    echo $foo, ' ', $bar;
?>

程序输出 11 20。原因是,方法内部无法访问$bar变量,所以它的值还是20。使用global之后,可以取得$foo的值,自增后$foo的值就是11。
Global的作用是定义全局变量,但是这个全局变量不是应用于整个网站,而是应用于当前页面,包括include或require的所有文件。
前言中提到变量的三个基本特性,其中的有一个特性为变量的类型,变量都有特定的类型, 如:字符串、数组、对象等等。编程语言的类型系统可以分为强类型和弱类型两种:
强类型语言是一旦某个变量被申明为某个类型的变量,则在程序运行过程中,该不能将该变量的类型以外的值赋予给它 (当然并不完全如此,这可能会涉及到类型的转换,后面的小节会有相应介绍),C/C++/Java等语言就属于这类。
PHP及Ruby,JavaScript等脚本语言属于弱类型语言:一个变量可以表示任意的数据类型。
PHP之所以成为一个简单而强大的语言,很大一部分的原因是它拥有弱类型的变量。 但是有些时候这也是一把双刃剑,使用不当也会带来一些问题。就像仪器一样,越是功能强大, 出现错误的可能性也就越大。
在官方的PHP实现内部,所有变量使用同一种数据结构(zval)来保存,而这个结构同时表示PHP中的各种数据类型。 它不仅仅包含变量的值,也包含变量的类型。这就是PHP弱类型的核心。
那zval结构具体是如何实现弱类型的呢,下面我们一起来揭开面纱。
变量存储结构
PHP在声明或使用变量的时候,并不需要显式指明其数据类型。
PHP是弱类型语言,这并不表示PHP没有类型,在PHP中,存在8种变量类型,可以分为三类
* 标量类型:boolean、integer、float(double)、string
* 复合类型: array、object
* 特殊类型: resource、NULL
官方PHP是用C实现的,而C是强类型的语言,那这是怎么实现PHP中的弱类型的呢?
变量的值存储到以下所示zval结构体中。 zval结构体定义在Zend/zend.h文件,其结构如下:

复制代码 代码如下:

typedef struct _zval_struct zval;
...
struct _zval_struct {
    /* Variable information */
    zvalue_value value; /* value */
    zend_uint refcount__gc;
    zend_uchar type; /* active type */
    zend_uchar is_ref__gc;
};

PHP使用这个结构来存储变量的所有数据。和其他编译性静态语言不同, PHP在存储变量时将PHP用户空间的变量类型也保存在同一个结构体中。这样我们就能通过这些信息获取到变量的类型。
zval结构体中有四个字段,其含义分别为:

属性名 含义 默认值
refcount__gc 表示引用计数 1
is_ref__gc 表示是否为引用 0
value 存储变量的值
type 变量具体的类型

在PHP5.3之后,引入了新的垃圾收集机制,引用计数和引用的字段名改为refcount__gc和is_ref__gc。在此之前为refcount和is__ref。

而变量的值则存储在另外一个结构体zvalue_value中。值存储见下面的介绍。
PHP用户空间指的在PHP语言这一层面,而本书中大部分地方都在探讨PHP的实现。 这些实现可以理解为内核空间。由于PHP使用C实现,而这个空间的范畴就会限制在C语言。 而PHP用户空间则会受限于PHP语法及功能提供的范畴之内。 例如有些PHP扩展会提供一些PHP函数或者类,这就是向PHP用户空间导出了方法或类。
变量类型
zval结构体的type字段就是实现弱类型最关键的字段了,type的值可以为: IS_NULL、IS_BOOL、IS_LONG、IS_DOUBLE、IS_STRING、IS_ARRAY、IS_OBJECT和IS_RESOURCE 之一。 从字面上就很好理解,他们只是类型的唯一标示,根据类型的不同将不同的值存储到value字段。 除此之外,和他们定义在一起的类型还有IS_CONSTANT和IS_CONSTANT_ARRAY。
这和我们设计数据库时的做法类似,为了避免重复设计类似的表,使用一个标示字段来记录不同类型的数据。

变量的值存储
前面提到变量的值存储在zvalue_value联合体中,结构体定义如下:

复制代码 代码如下:

typedef union _zvalue_value {
    long lval; /* long value */
    double dval; /* double value */
    struct {
        char *val;
        int len;
    } str;
    HashTable *ht; /* hash table value */
    zend_object_value obj;
} zvalue_value;

这里使用联合体而不是用结构体是出于空间利用率的考虑,因为一个变量同时只能属于一种类型。 如果使用结构体的话将会不必要的浪费空间,而PHP中的所有逻辑都围绕变量来进行的,这样的话, 内存浪费将是十分大的。这种做法成本小但收益非常大。
各种类型的数据会使用不同的方法来进行变量值的存储,其对应赋值方式如下:

1. 一般类型

变量类型 ?
boolean ZVAL_BOOL 布尔型/整型的变量值存储于(zval).value.lval中,其类型也会以相应的IS_*进行存储。
Z_TYPE_P(z)=IS_BOOL/LONG; Z_LVAL_P(z)=((b)!=0);
integer ZVAL_LONG
float ZVAL_DOUBLE
null ZVAL_NULL NULL值的变量值不需要存储,只需要把(zval).type标为IS_NULL。
Z_TYPE_P(z)=IS_NULL;
resource ZVAL_RESOURCE 资源类型的存储与其他一般变量无异,但其初始化及存取实现则不同。
Z_TYPE_P(z) = IS_RESOURCE; Z_LVAL_P(z) = l;

2. 字符串Sting
字符串的类型标示和其他数据类型一样,不过在存储字符串时多了一个字符串长度的字段。

复制代码 代码如下:

struct {
    char *val;
    int len;
} str;

C中字符串是以\0结尾的字符数组,这里多存储了字符串的长度,这和我们在设计数据库时增加的冗余字段异曲同工。 因为要实时获取到字符串的长度的时间复杂度是O(n),而字符串的操作在PHP中是非常频繁的,这样能避免重复计算字符串的长度, 这能节省大量的时间,是空间换时间的做法。 这么看在PHP中strlen()函数可以在常数时间内获取到字符串的长度。 计算机语言中字符串的操作都非常之多,所以大部分高级语言中都会存储字符串的长度。

3. 数组Array

数组是PHP中最常用,也是最强大变量类型,它可以存储其他类型的数据,而且提供各种内置操作函数。数组的存储相对于其他变量要复杂一些, 数组的值存储在zvalue_value.ht字段中,它是一个HashTable类型的数据。 PHP的数组使用哈希表来存储关联数据。哈希表是一种高效的键值对存储结构。PHP的哈希表实现中使用了两个数据结构HashTable和Bucket。 PHP所有的工作都由哈希表实现,在下节HashTable中将进行哈希表基本概念的介绍以及PHP的哈希表实现。

4. 对象Object

在面向对象语言中,我们能自己定义自己需要的数据类型,包括类的属性,方法等数据。而对象则是类的一个具体实现。 对象有自身的状态和所能完成的操作。
PHP的对象是一种复合型的数据,使用一种zend_object_value的结构体来存放。其定义如下:

复制代码 代码如下:

typedef struct _zend_object_value {
    zend_object_handle handle; // unsigned int类型,EG(objects_store).object_buckets的索引
    zend_object_handlers *handlers;
} zend_object_value;

PHP的对象只有在运行时才会被创建,前面的章节介绍了EG宏,这是一个全局结构体用于保存在运行时的数据。 其中就包括了用来保存所有被创建的对象的对象池,EG(objects_store),而object对象值内容的zend_object_handle域就是当前 对象在对象池中所在的索引,handlers字段则是将对象进行操作时的处理函数保存起来。 这个结构体及对象相关的类的结构_zend_class_entry,后面会介绍到。
PHP的弱变量容器的实现方式是兼容并包的形式体现,针对每种类型的变量都有其对应的标记和存储空间。 使用强类型的语言在效率上通常会比弱类型高,因为很多信息能在运行之前就能确定,这也能帮助排除程序错误。 而这带来的问题是编写代码相对会受制约。

PHP主要的用途是作为Web开发语言,在普通的Web应用中瓶颈通常在业务和数据访问这一层。不过在大型应用下语言也会是一个关键因素。 facebook因此就使用了自己的php实现。将PHP编译为C++代码来提高性能。不过facebook的hiphop并不是完整的php实现, 由于它是直接将php编译为C++,有一些PHP的动态特性比如eval结构就无法实现。当然非要实现也是有方法的, hiphop不实现应该也是做了一个权衡。

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/728099.htmlTechArticle先回答前面一节的那个问题吧。 复制代码 代码如下: ?php $foo = 10; $bar = 20; function change() { global $foo; //echo '函数内部$foo = '.$foo.'br /'; //如果不...
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
4 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何在 Windows 11 中變更網路類型為專用或公用 如何在 Windows 11 中變更網路類型為專用或公用 Aug 24, 2023 pm 12:37 PM

設定無線網路很常見,但選擇或變更網路類型可能會令人困惑,尤其是在您不知道後果的情況下。如果您正在尋找有關如何在Windows11中將網路類型從公用變更為私有或反之亦然的建議,請繼續閱讀以取得一些有用的資訊。 Windows11中有哪些不同的網路設定檔? Windows11附帶了許多網路設定文件,這些設定檔本質上是可用於配置各種網路連線的設定集。如果您在家中或辦公室有多個連接,這將非常有用,因此您不必每次連接到新網路時都進行所有設定。專用和公用網路設定檔是Windows11中的兩種常見類型,但通

視訊矩陣帳號怎麼做?它的矩陣帳號都有哪些類型呢? 視訊矩陣帳號怎麼做?它的矩陣帳號都有哪些類型呢? Mar 21, 2024 pm 04:57 PM

隨著短影片平台的盛行,影片矩陣帳號行銷已成為一種新興行銷方式。透過在不同平台上建立和管理多個帳號,企業和個人能夠實現品牌推廣、粉絲成長和產品銷售等目標。本文將為您探討如何有效運用視訊矩陣帳號,並介紹不同類型的視訊矩陣帳號。一、視訊矩陣帳號怎麼做?要做好視訊矩陣帳號,需要遵循以下幾個步驟:首先要明確你的影片矩陣帳號的目標是什麼,是為了品牌傳播、粉絲成長還是產品銷售。明確目標有助於制定相應的策略。 2.選擇平台:根據你的目標受眾,選擇合適的短影片平台。目前主流的短視頻平台有抖音、快手、火山小影片等。

用Python實現動態數組:從入門到精通 用Python實現動態數組:從入門到精通 Apr 21, 2023 pm 12:04 PM

Part1聊聊Python序列類型的本質在本部落格中,我們來聊聊探討Python的各種「序列」類,內建的三大常用資料結構-清單類別(list)、元組類(tuple)和字符串類(str)的本質。我不知道你發現沒有,這些類別都有一個很明顯的共通性,都可以用來保存多個資料元素,最主要的功能是:每個類別都支援下標(索引)存取該序列的元素,例如使用語法Seq[i]。其實上面每個類別都是使用陣列這種簡單的資料結構表示。但熟悉Python的讀者可能知道這3種資料結構又有些不同:例如元組和字串是不能修改的,列表可以

Golang 函數傳回值的型別是什麼? Golang 函數傳回值的型別是什麼? Apr 13, 2024 pm 05:42 PM

Go函數可以傳回多個不同類型的值,傳回值類型在函數簽章中指定,並透過return語句傳回。例如,函數可以傳回一個整數和一個字串:funcgetDetails()(int,string)。在實戰中,一個計算圓面積的函數可以回傳面積和一個可選錯誤:funccircleArea(radiusfloat64)(float64,error)。注意事項:如果函數簽章未指定類型,則傳回空值;建議使用明確類型宣告的return語句以提高可讀性。

Python中型別提示的最佳實踐 Python中型別提示的最佳實踐 Apr 23, 2023 am 09:28 AM

使用動態語言一時爽,程式碼重構火葬場。相信你一定聽過這句話,和單元測試一樣,雖然寫程式碼的時候花費你少量的時間,但是從長遠來看,這是非常值得的。本文分享如何更好的理解和使用Python的類型提示。 1、類型提示僅在語法層面有效類型提示(自PEP3107開始引入)用於在變數、參數、函數參數以及它們的傳回值、類別屬性和方法中新增類型。 Python的變數類型是動態的,可以在運行時修改,為程式碼添加類型提示,僅在語法層面支持,對程式碼的運行沒有任何影響,Python解釋器在運行程式碼的時候會忽略類型提示。因此類型提

C++ 函式的型別和特性 C++ 函式的型別和特性 Apr 11, 2024 pm 03:30 PM

C++函式有以下型別:簡單函式、const函式、靜態函式、虛函式;特性包括:inline函式、預設參數、參考回傳、重載函式。例如,calculateArea函數使用π計算給定半徑圓的面積,並將其作為輸出傳回。

主要的自媒體平台有哪些?自媒體平台的類型有哪些呢? 主要的自媒體平台有哪些?自媒體平台的類型有哪些呢? Mar 21, 2024 pm 06:36 PM

隨著網路的快速發展,自媒體成為了資訊傳播的重要管道。自媒體平台為個人和企業提供了一個展示自己、傳播訊息的舞台。目前,市場上主要的自媒體平台有微信公眾號、今日頭條、一點資訊、企鵝媒體平台等。這些平台各有特色,為廣大自媒體從業人員提供了豐富的創作空間。接下來,我們將對這些平台進行詳細介紹,並探討自媒體平台的類型。一、主要的自媒體平台有哪些?微信公眾號是騰訊推出的自媒體平台,為個人和企業用戶提供資訊發布和傳播服務。它分為服務號碼和訂閱號碼兩種類型,服務號主要為企業提供服務,而訂閱號則側重於資訊傳播。由

深入探討Golang變數的儲存位置與機制 深入探討Golang變數的儲存位置與機制 Feb 28, 2024 pm 09:45 PM

標題:深入探討Golang變數的儲存位置和機制隨著Go語言(Golang)在雲端運算、大數據和人工智慧領域的應用逐漸增多,深入了解Golang變數的儲存位置和機制變得尤為重要。在本文中,我們將詳細探討Golang中變數的記憶體分配、儲存位置以及相關的機制。透過具體程式碼範例,幫助讀者更好地理解Golang變數在記憶體中是如何儲存和管理的。 1.Golang變數的內存

See all articles