標(biāo)量數(shù)據(jù)類(lèi)型是數(shù)據(jù)結(jié)構(gòu)最基礎(chǔ)的單元,只能存儲(chǔ)一個(gè)數(shù)據(jù)。在 PHP 中的標(biāo)量數(shù)據(jù)類(lèi)型分為四種
讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來(lái)自于我們對(duì)這個(gè)行業(yè)的熱愛(ài)。我們立志把好的技術(shù)通過(guò)有效、簡(jiǎn)單的方式提供給客戶,將通過(guò)不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長(zhǎng)期合作伙伴,公司提供的服務(wù)項(xiàng)目有:國(guó)際域名空間、網(wǎng)站空間、營(yíng)銷(xiāo)軟件、網(wǎng)站建設(shè)、霞浦網(wǎng)站維護(hù)、網(wǎng)站推廣。
boolean(布爾型) 最簡(jiǎn)單的數(shù)據(jù)類(lèi)型,只有兩個(gè)值:true(真) / false(假)
string(字符串) 字符串是連續(xù)的字符序列
integer(整型) 整型數(shù)據(jù)類(lèi)型包含所有的整數(shù),其可以是整數(shù)也可以是負(fù)數(shù)
float(浮點(diǎn)型) 浮點(diǎn)型數(shù)據(jù)類(lèi)型也是用來(lái)存儲(chǔ)數(shù)字,與整型不同它包含小數(shù)
本文小編為大家詳細(xì)介紹“php數(shù)組的元素可不可以是數(shù)字”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“php數(shù)組的元素可不可以是數(shù)字”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來(lái)學(xué)習(xí)新知識(shí)吧。
php數(shù)組的元素可以是數(shù)字。因?yàn)镻HP是弱數(shù)據(jù)類(lèi)型的編程語(yǔ)言,所以PHP中的數(shù)組可以存儲(chǔ)任意多個(gè)、任意類(lèi)型的數(shù)據(jù),即數(shù)組元素的類(lèi)型沒(méi)有限制,可以是數(shù)字(整數(shù)和浮點(diǎn)數(shù))、字符串、布爾值、數(shù)組、Object對(duì)象等類(lèi)型。
?
本教程操作環(huán)境:windows7系統(tǒng)、PHP8.1版、DELL G3電腦
php數(shù)組的元素可以是數(shù)字。
數(shù)組是 PHP 中最重要的數(shù)據(jù)類(lèi)型之一,在 PHP 中的應(yīng)用非常廣泛。因?yàn)?PHP 是弱數(shù)據(jù)類(lèi)型的編程語(yǔ)言,所以 PHP 中的數(shù)組變量可以存儲(chǔ)任意多個(gè)、任意類(lèi)型的數(shù)據(jù),并且可以實(shí)現(xiàn)其他強(qiáng)數(shù)據(jù)類(lèi)型中的堆、棧、隊(duì)列等數(shù)據(jù)結(jié)構(gòu)的功能。
簡(jiǎn)單來(lái)說(shuō),PHP數(shù)組元素的類(lèi)型沒(méi)有限制,可以是數(shù)字、字符串、布爾值、數(shù)組、Object對(duì)象等類(lèi)型。
示例1:索引數(shù)組
?php
header("Content-type:text/html;charset=utf-8");
$arr= array(1,2,"3",4,0.5,"hello",TRUE,3.14);
var_dump($arr);
?
?
說(shuō)明:索引數(shù)組的下標(biāo)(鍵名)由數(shù)字組成,默認(rèn)從 0 開(kāi)始,每個(gè)數(shù)字對(duì)應(yīng)一個(gè)數(shù)組元素在數(shù)組中的位置,不需要特別指定,PHP 會(huì)自動(dòng)為索引數(shù)組的鍵名賦一個(gè)整數(shù)值,然后從這個(gè)值開(kāi)始自動(dòng)遞增。
示例2:關(guān)聯(lián)數(shù)組
?php
header("Content-type:text/html;charset=utf-8");
$arr=array(1=1,"a"=3.5,2=2,"b"=0,"c"="blue");
var_dump($arr);
?
?
說(shuō)明:關(guān)聯(lián)數(shù)組的下標(biāo)(鍵名)由數(shù)值和字符串混合的形式組成,如果一個(gè)數(shù)組中有一個(gè)鍵名不是數(shù)字,那么這個(gè)數(shù)組就是關(guān)聯(lián)數(shù)組。
php中的數(shù)字
在php中,數(shù)字可分為integer(整型)和float(浮點(diǎn)型)
類(lèi)型 功能
integer(整型) 整型包含所有的整數(shù),可以是正數(shù)也可以是負(fù)數(shù)
float(浮點(diǎn)型) 浮點(diǎn)型也是用來(lái)表示數(shù)字的,與整型不同除了可以表示整數(shù)外它還可以用來(lái)表示小數(shù)和指數(shù)
1)整型
在 PHP 中,整型變量稱為 integer 或 int 類(lèi)型,用來(lái)表示一個(gè)整數(shù),整型的規(guī)則如下所示:
整型必須至少有一個(gè)數(shù)字(0~9);
整型不能包含逗號(hào)或空格;
整型不能包含小數(shù)點(diǎn);
整型可以是正數(shù)或負(fù)數(shù)。
整型的取值范圍必須介于 -2E31 到 2E31 之間,可以用三種格式來(lái)表示,即十進(jìn)制、十六進(jìn)制(以 0x 為前綴)和八進(jìn)制(以 0 為前綴)。
?php
$x = 5985; // 定義一個(gè)整型數(shù)據(jù)類(lèi)型的變量
var_dump($x); // 輸出此變量
$x = -345;
var_dump($x);
$x = 0x8C; //十六進(jìn)制數(shù)字
var_dump($x);
$x = 047; //八進(jìn)制數(shù)字
var_dump($x);
?
?
注意,在 PHP7 版本中,含有十六進(jìn)制字符的字符串不再被視為數(shù)字,而是當(dāng)作普通的字符串。
2)浮點(diǎn)型
浮點(diǎn)型在 PHP 中被稱為 float 類(lèi)型,也可稱為實(shí)數(shù),可以用來(lái)存儲(chǔ)整數(shù)和小數(shù),有效的取值范圍是 1.8E-308 到 1.8E+308 之間。浮點(diǎn)數(shù)的精確度比整型數(shù)據(jù)類(lèi)型要高。
?php
$num1 = 10.365;
$num2 = 2.4e3;
$num3 = 8E-5;
var_dump($num1, $num2, $num3);
?
?
讀到這里,這篇“php數(shù)組的元素可不可以是數(shù)字”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過(guò)才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。
本篇文章是對(duì)PHP中的內(nèi)存管理 PHP動(dòng)態(tài)分配和釋放內(nèi)存進(jìn)行了詳細(xì)的分析介紹 需要的朋友參考下 ?
摘要 內(nèi)存管理對(duì)于長(zhǎng)期運(yùn)行的程序 例如服務(wù)器守護(hù)程序 是相當(dāng)重要的影響 因此 理解PHP是如何分配與釋放內(nèi)存的對(duì)于創(chuàng)建這類(lèi)程序極為重要 本文將重點(diǎn)探討PHP的內(nèi)存管理問(wèn)題
一 內(nèi)存 在PHP中 填充一個(gè)字符串變量相當(dāng)簡(jiǎn)單 這只需要一個(gè)語(yǔ)句"<?php $str = hello world ; ?>"即可 并且該字符串能夠被自由地修改 拷貝和移動(dòng) 而在C語(yǔ)言中 盡管你能夠編寫(xiě)例如"char *str = "hello world ";"這樣的一個(gè)簡(jiǎn)單的靜態(tài)字符串 但是 卻不能修改該字符串 因?yàn)樗嬗诔绦蚩臻g內(nèi) 為了創(chuàng)建一個(gè)可操縱的字符串 你必須分配一個(gè)內(nèi)存塊 并且通過(guò)一 個(gè)函數(shù)(例如strdup())來(lái)復(fù)制其內(nèi)容
復(fù)制代碼 代碼如下: { char *str; str = strdup("hello world"); if (!str) { fprintf(stderr "Unable to allocate memory!"); } }
由于后面我們將分析的各種原因 傳統(tǒng)型內(nèi)存管理函數(shù)(例如malloc() free() strdup() realloc() calloc() 等等)幾乎都不能直接為PHP源代碼所使用
二 釋放內(nèi)存 在幾乎所有的平臺(tái)上 內(nèi)存管理都是通過(guò)一種請(qǐng)求和釋放模式實(shí)現(xiàn)的 首先 一個(gè)應(yīng)用程序請(qǐng)求它下面的層(通常指"操作系統(tǒng)") "我想使用一些內(nèi)存空間" 如果存在可用的空間 操作系統(tǒng)就會(huì)把它提供給該程序并且打上一個(gè)標(biāo)記以便不會(huì)再把這部分內(nèi)存分配給其它程序 當(dāng) 應(yīng)用程序使用完這部分內(nèi)存 它應(yīng)該被返回到OS 這樣以來(lái) 它就能夠被繼續(xù)分配給其它程序 如果該程序不返回這部分內(nèi)存 那么OS無(wú)法知道是否這塊內(nèi)存不 再使用并進(jìn)而再分配給另一個(gè)進(jìn)程 如果一個(gè)內(nèi)存塊沒(méi)有釋放 并且所有者應(yīng)用程序丟失了它 那么 我們就說(shuō)此應(yīng)用程序"存在漏洞" 因?yàn)檫@部分內(nèi)存無(wú)法再為 其它程序可用 在一個(gè)典型的客戶端應(yīng)用程序中 較小的不太經(jīng)常的內(nèi)存泄漏有時(shí)能夠?yàn)镺S所"容忍" 因?yàn)樵谶@個(gè)進(jìn)程稍后結(jié)束時(shí)該泄漏內(nèi)存會(huì)被隱式返回到OS 這并沒(méi)有什么 因?yàn)镺S知道它把該內(nèi)存分配給了哪個(gè)程序 并且它能夠確信當(dāng)該程序終止時(shí)不再需要該內(nèi)存 而對(duì)于長(zhǎng)時(shí)間運(yùn)行的服務(wù)器守護(hù)程序 包括象Apache這樣的web服務(wù)器和擴(kuò)展php模塊來(lái)說(shuō) 進(jìn)程往往被設(shè)計(jì)為相當(dāng)長(zhǎng)時(shí)間一直運(yùn)行 因?yàn)镺S不能清理內(nèi)存使用 所以 任何程序的泄漏 無(wú)論是多么小 都將導(dǎo)致重復(fù)操作并最終耗盡所有的系統(tǒng)資源 現(xiàn) 在 我們不妨考慮用戶空間內(nèi)的stristr()函數(shù) 為了使用大小寫(xiě)不敏感的搜索來(lái)查找一個(gè)字符串 它實(shí)際上創(chuàng)建了兩個(gè)串的各自的一個(gè)小型副本 然后執(zhí) 行一個(gè)更傳統(tǒng)型的大小寫(xiě)敏感的搜索來(lái)查找相對(duì)的偏移量 然而 在定位該字符串的偏移量之后 它不再使用這些小寫(xiě)版本的字符串 如果它不釋放這些副本 那 么 每一個(gè)使用stristr()的腳本在每次調(diào)用它時(shí)都將泄漏一些內(nèi)存 最后 web服務(wù)器進(jìn)程將擁有所有的系統(tǒng)內(nèi)存 但卻不能夠使用它 你可以理直氣壯地說(shuō) 理想的解決方案就是編寫(xiě)良好 干凈的 一致的代碼 這當(dāng)然不錯(cuò) 但是 在一個(gè)象PHP解釋器這樣的環(huán)境中 這種觀點(diǎn)僅對(duì)了一半
三 錯(cuò)誤處理 為了實(shí)現(xiàn)"跳出"對(duì)用戶空間腳本及其依賴的擴(kuò)展函數(shù)的一個(gè)活動(dòng)請(qǐng)求 需要使用一種方法來(lái) 完全"跳出"一個(gè)活動(dòng)請(qǐng)求 這是在Zend引擎內(nèi)實(shí)現(xiàn)的 在一個(gè)請(qǐng)求的開(kāi)始設(shè)置一個(gè)"跳出"地址 然后在任何die()或exit()調(diào)用或在遇到任何關(guān) 鍵錯(cuò)誤(E_ERROR)時(shí)執(zhí)行一個(gè)longjmp()以跳轉(zhuǎn)到該"跳出"地址 盡管這個(gè)"跳出"進(jìn)程能夠簡(jiǎn)化程序執(zhí)行的流程 但是 在絕大多數(shù)情況下 這會(huì)意味著將會(huì)跳過(guò)資源清除代碼部分(例如free()調(diào)用)并最終導(dǎo)致出現(xiàn)內(nèi)存漏洞 現(xiàn)在 讓我們來(lái)考慮下面這個(gè)簡(jiǎn)化版本的處理函數(shù)調(diào)用的引擎代碼
復(fù)制代碼 代碼如下: void call_function(const char *fname int fname_len TSRMLS_DC){ zend_function *fe; char *lcase_fname; /* PHP函數(shù)名是大小寫(xiě)不敏感的 *為了簡(jiǎn)化在函數(shù)表中對(duì)它們的定位 *所有函數(shù)名都隱含地翻譯為小寫(xiě)的 */ lcase_fname = estrndup(fname fname_len); zend_str_tolower(lcase_fname fname_len); if (zend_hash_find(EG(function_table) lcase_fname fname_len + (void **)fe) == FAILURE) { zend_execute(fe >op_array TSRMLS_CC); } else { php_error_docref(NULL TSRMLS_CC E_ERROR "Call to undefined function: %s()" fname); } efree(lcase_fname); }
當(dāng) 執(zhí)行到php_error_docref()這一行時(shí) 內(nèi)部錯(cuò)誤處理器就會(huì)明白該錯(cuò)誤級(jí)別是critical 并相應(yīng)地調(diào)用longjmp()來(lái)中斷當(dāng)前 程序流程并離開(kāi)call_function()函數(shù) 甚至根本不會(huì)執(zhí)行到efree(lcase_fname)這一行 你可能想把efree()代碼行移 動(dòng)到zend_error()代碼行的上面 但是 調(diào)用這個(gè)call_function()例程的代碼行會(huì)怎么樣呢?fname本身很可能就是一個(gè)分配的 字符串 并且 在它被錯(cuò)誤消息處理使用完之前 你根本不能釋放它 注意 這個(gè)php_error_docref()函數(shù)是trigger_error()函數(shù)的一個(gè)內(nèi)部等價(jià)實(shí)現(xiàn) 它的第一個(gè)參數(shù)是一個(gè)將被添加到docref的可選的文檔引用 第三個(gè)參數(shù)可以是任何我們熟悉的E_*家族常量 用于指示錯(cuò)誤的嚴(yán)重程度 第四個(gè)參數(shù)(最后一個(gè))遵循printf()風(fēng)格的格式化和變量參數(shù)列表式樣 四 Zend內(nèi)存管理器 在 上面的"跳出"請(qǐng)求期間解決內(nèi)存泄漏的方案之一是 使用Zend內(nèi)存管理(ZendMM)層 引擎的這一部分非常類(lèi)似于操作系統(tǒng)的內(nèi)存管理行為 分配內(nèi)存 給調(diào)用程序 區(qū)別在于 它處于進(jìn)程空間中非常低的位置而且是"請(qǐng)求感知"的 這樣以來(lái) 當(dāng)一個(gè)請(qǐng)求結(jié)束時(shí) 它能夠執(zhí)行與OS在一個(gè)進(jìn)程終止時(shí)相同的行為 也就是說(shuō) 它會(huì)隱式地釋放所有的為該請(qǐng)求所占用的內(nèi)存 圖 展示了ZendMM與OS以及PHP進(jìn)程之間的關(guān)系 圖 Zend內(nèi)存管理器代替系統(tǒng)調(diào)用來(lái)實(shí)現(xiàn)針對(duì)每一種請(qǐng)求的內(nèi)存分配 除 了提供隱式內(nèi)存清除功能之外 ZendMM還能夠根據(jù)php ini中memory_limit的設(shè)置控制每一種內(nèi)存請(qǐng)求的用法 如果一個(gè)腳本試圖請(qǐng)求比 系統(tǒng)中可用內(nèi)存更多的內(nèi)存 或大于它每次應(yīng)該請(qǐng)求的最大量 那么 ZendMM將自動(dòng)地發(fā)出一個(gè)E_ERROR消息并且啟動(dòng)相應(yīng)的"跳出"進(jìn)程 這種方法 的一個(gè)額外優(yōu)點(diǎn)在于 大多數(shù)內(nèi)存分配調(diào)用的返回值并不需要檢查 因?yàn)槿绻〉脑拰?huì)導(dǎo)致立即跳轉(zhuǎn)到引擎的退出部分 把PHP內(nèi)部代碼和 OS的實(shí)際的內(nèi)存管理層"鉤"在一起的原理并不復(fù)雜 所有內(nèi)部分配的內(nèi)存都要使用一組特定的可選函數(shù)實(shí)現(xiàn) 例如 PHP代碼不是使用malloc( ) 來(lái)分配一個(gè) 字節(jié)內(nèi)存塊而是使用了emalloc( ) 除了實(shí)現(xiàn)實(shí)際的內(nèi)存分配任務(wù)外 ZendMM還會(huì)使用相應(yīng)的綁定請(qǐng)求類(lèi)型來(lái)標(biāo)志該內(nèi)存塊 這 樣以來(lái) 當(dāng)一個(gè)請(qǐng)求"跳出"時(shí) ZendMM可以隱式地釋放它 經(jīng)常情況下 內(nèi)存一般都需要被分配比單個(gè)請(qǐng)求持續(xù)時(shí)間更長(zhǎng)的一段時(shí)間 這 種類(lèi)型的分配(因其在一次請(qǐng)求結(jié)束之后仍然存在而被稱為"永久性分配") 可以使用傳統(tǒng)型內(nèi)存分配器來(lái)實(shí)現(xiàn) 因?yàn)檫@些分配并不會(huì)添加ZendMM使用的那 些額外的相應(yīng)于每種請(qǐng)求的信息 然而有時(shí) 直到運(yùn)行時(shí)刻才會(huì)確定是否一個(gè)特定的分配需要永久性分配 因此ZendMM導(dǎo)出了一組幫助宏 其行為類(lèi)似于其它 的內(nèi)存分配函數(shù) 但是使用最后一個(gè)額外參數(shù)來(lái)指示是否為永久性分配 如果你確實(shí)想實(shí)現(xiàn)一個(gè)永久性分配 那么這個(gè)參數(shù)應(yīng)該被設(shè)置為 在這 種情況下 請(qǐng)求是通過(guò)傳統(tǒng)型malloc()分配器家族進(jìn)行傳遞的 然而 如果運(yùn)行時(shí)刻邏輯認(rèn)為這個(gè)塊不需要永久性分配 那么 這個(gè)參數(shù)可以被設(shè)置為零 并且調(diào)用將會(huì)被調(diào)整到針對(duì)每種請(qǐng)求的內(nèi)存分配器函數(shù) 例如 pemalloc(buffer_len )將映射到malloc(buffer_len) 而pemalloc(buffer_len )將被使用下列語(yǔ)句映射到emalloc(buffer_len) #define in Zend/zend_alloc h: #define pemalloc(size persistent) ((persistent)?malloc(size): emalloc(size)) 所有這些在ZendMM中提供的分配器函數(shù)都能夠從下表中找到其更傳統(tǒng)的對(duì)應(yīng)實(shí)現(xiàn) 表格 展示了ZendMM支持下的每一個(gè)分配器函數(shù)以及它們的e/pe對(duì)應(yīng)實(shí)現(xiàn) 表格 傳統(tǒng)型相對(duì)于PHP特定的分配器
分配器函數(shù) e/pe對(duì)應(yīng)實(shí)現(xiàn) void *malloc(size_t count); void *emalloc(size_t count);void *pemalloc(size_t count char persistent); void *calloc(size_t count); void *ecalloc(size_t count);void *pecalloc(size_t count char persistent); void *realloc(void *ptr size_t count); void *erealloc(void *ptr size_t count); void *perealloc(void *ptr size_t count char persistent); void *strdup(void *ptr); void *estrdup(void *ptr);void *pestrdup(void *ptr char persistent); void free(void *ptr); void efree(void *ptr); void pefree(void *ptr char persistent);
你可能會(huì)注意到 即使是pefree()函數(shù)也要求使用永久性標(biāo)志 這是因?yàn)樵谡{(diào)用pefree()時(shí) 它實(shí)際上并不知道是否ptr是一種永久性分 配 針對(duì)一個(gè)非永久性分配調(diào)用free()能夠?qū)е码p倍的空間釋放 而針對(duì)一種永久性分配調(diào)用efree()有可能會(huì)導(dǎo)致一個(gè)段錯(cuò)誤 因?yàn)閮?nèi)存管理器會(huì)試 圖查找并不存在的管理信息 因此 你的代碼需要記住它分配的數(shù)據(jù)結(jié)構(gòu)是否是永久性的 除了分配器函數(shù)核心部分外 還存在其它一些非常方便的ZendMM特定的函數(shù) 例如 void *estrndup(void *ptr int len); 該函數(shù)能夠分配len+ 個(gè)字節(jié)的內(nèi)存并且從ptr處復(fù)制len個(gè)字節(jié)到最新分配的塊 這個(gè)estrndup()函數(shù)的行為可以大致描述如下
復(fù)制代碼 代碼如下: void *estrndup(void *ptr int len) { char *dst = emalloc(len + ); memcpy(dst ptr len); dst[len] = ; return dst; }
在 此 被隱式放置在緩沖區(qū)最后的NULL字節(jié)可以確保任何使用estrndup()實(shí)現(xiàn)字符串復(fù)制操作的函數(shù)都不需要擔(dān)心會(huì)把結(jié)果緩沖區(qū)傳遞給一個(gè)例如 printf()這樣的希望以為NULL為結(jié)束符的函數(shù) 當(dāng)使用estrndup()來(lái)復(fù)制非字符串?dāng)?shù)據(jù)時(shí) 最后一個(gè)字節(jié)實(shí)質(zhì)上都浪費(fèi)了 但其中的利明顯 大于弊 void *safe_emalloc(size_t size size_t count size_t addtl); void *safe_pemalloc(size_t size size_t count size_t addtl char persistent); 這 些函數(shù)分配的內(nèi)存空間最終大小是((size*count)+addtl) 你可以會(huì)問(wèn) "為什么還要提供額外函數(shù)呢?為什么不使用一個(gè) emalloc/pemalloc呢?"原因很簡(jiǎn)單 為了安全 盡管有時(shí)候可能性相當(dāng)小 但是 正是這一"可能性相當(dāng)小"的結(jié)果導(dǎo)致宿主平臺(tái)的內(nèi)存溢出 這可能會(huì)導(dǎo)致分配負(fù)數(shù)個(gè)數(shù)的字節(jié)空間 或更有甚者 會(huì)導(dǎo)致分配一個(gè)小于調(diào)用程序要求大小的字節(jié)空間 而safe_emalloc()能夠避免這種類(lèi)型的陷 井 通過(guò)檢查整數(shù)溢出并且在發(fā)生這樣的溢出時(shí)顯式地預(yù)以結(jié)束 注意 并不是所有的內(nèi)存分配例程都有一個(gè)相應(yīng)的p*對(duì)等實(shí)現(xiàn) 例如 不存在pestrndup() 并且在PHP 版本前也不存在safe_pemalloc()
五 引用計(jì)數(shù) 慎重的內(nèi)存分配與釋放對(duì)于PHP(它是一種多請(qǐng)求進(jìn)程)的長(zhǎng)期性能有極其重大的影響 但是 這還僅是問(wèn)題的一半 為了使一個(gè)每秒處理上千次點(diǎn)擊的服務(wù)器高效地運(yùn)行 每一次請(qǐng)求都需要使用盡可能少的內(nèi)存并且要盡可能減少不必要的數(shù)據(jù)復(fù)制操作 請(qǐng)考慮下列PHP代碼片斷
復(fù)制代碼 代碼如下: <?php $a = Hello World ; $b = $a; unset($a); ?>
在第一次調(diào)用之后 只有一個(gè)變量被創(chuàng)建 并且一個(gè) 字節(jié)的內(nèi)存塊指派給它以便存儲(chǔ)字符串"Hello World" 還包括一個(gè)結(jié)尾處的NULL字符 現(xiàn)在 讓我們來(lái)觀察后面的兩行 $b被置為與變量$a相同的值 然后變量$a被釋放 如 果PHP因每次變量賦值都要復(fù)制變量?jī)?nèi)容的話 那么 對(duì)于上例中要復(fù)制的字符串還需要復(fù)制額外的 個(gè)字節(jié) 并且在數(shù)據(jù)復(fù)制期間還要進(jìn)行另外的處理器加 載 這一行為乍看起來(lái)有點(diǎn)荒謬 因?yàn)楫?dāng)?shù)谌写a出現(xiàn)時(shí) 原始變量被釋放 從而使得整個(gè)數(shù)據(jù)復(fù)制顯得完全不必要 其實(shí) 我們不妨再遠(yuǎn)一層考慮 讓我們?cè)O(shè)想 當(dāng)一個(gè) MB大小的文件的內(nèi)容被裝載到兩個(gè)變量中時(shí)會(huì)發(fā)生什么 這將會(huì)占用 MB的空間 此時(shí) 已經(jīng)足夠了 引擎會(huì)把那么多的時(shí)間和內(nèi)存浪費(fèi)在這 樣一種無(wú)用的努力上嗎? 你應(yīng)該知道 PHP的設(shè)計(jì)者早已深諳此理 記住 在引擎中 變量名和它們的值實(shí)際上是兩個(gè)不同的概念 值本身是一個(gè)無(wú)名的zval*存儲(chǔ)體(在本例中 是一個(gè)字符串值) 它被通過(guò)zend_hash_add()賦給變量$a 如果兩個(gè)變量名都指向同一個(gè)值 會(huì)發(fā)生什么呢?
復(fù)制代碼 代碼如下: { zval *helloval; MAKE_STD_ZVAL(helloval); ZVAL_STRING(helloval "Hello World" ); zend_hash_add(EG(active_symbol_table) "a" sizeof("a") helloval sizeof(zval*) NULL); zend_hash_add(EG(active_symbol_table) "b" sizeof("b") helloval sizeof(zval*) NULL); }
此 時(shí) 你可以實(shí)際地觀察$a或$b 并且會(huì)看到它們都包含字符串"Hello World" 遺憾的是 接下來(lái) 你繼續(xù)執(zhí)行第三行代碼"unset($a);" 此時(shí) unset()并不知道$a變量指向的數(shù)據(jù)還被另一個(gè)變量所使 用 因此它只是盲目地釋放掉該內(nèi)存 任何隨后的對(duì)變量$b的存取都將被分析為已經(jīng)釋放的內(nèi)存空間并因此導(dǎo)致引擎崩潰 這個(gè)問(wèn)題可以借助于 zval(它有好幾種形式)的第四個(gè)成員refcount加以解決 當(dāng)一個(gè)變量被首次創(chuàng)建并賦值時(shí) 它的refcount被初始化為 因?yàn)樗患俣▋H由 最初創(chuàng)建它時(shí)相應(yīng)的變量所使用 當(dāng)你的代碼片斷開(kāi)始把helloval賦給$b時(shí) 它需要把refcount的值增加為 這樣以來(lái) 現(xiàn)在該值被兩個(gè)變量 所引用
復(fù)制代碼 代碼如下: { zval *helloval; MAKE_STD_ZVAL(helloval); ZVAL_STRING(helloval "Hello World" ); zend_hash_add(EG(active_symbol_table) "a" sizeof("a") helloval sizeof(zval*) NULL); ZVAL_ADDREF(helloval); zend_hash_add(EG(active_symbol_table) "b" sizeof("b") helloval sizeof(zval*) NULL); }
現(xiàn)在 當(dāng)unset()刪除原變量的$a相應(yīng)的副本時(shí) 它就能夠從refcount參數(shù)中看到 還有另外其他人對(duì)該數(shù)據(jù)感興趣 因此 它應(yīng)該只是減少refcount的計(jì)數(shù)值 然后不再管它
六 寫(xiě)復(fù)制(Copy on Write) 通過(guò)refcounting來(lái)節(jié)約內(nèi)存的確是不錯(cuò)的主意 但是 當(dāng)你僅想改變其中一個(gè)變量的值時(shí)情況會(huì)如何呢?為此 請(qǐng)考慮下面的代碼片斷
復(fù)制代碼 代碼如下: <?php $a = ; $b = $a; $b += ; ?>
通過(guò)上面的邏輯流程 你當(dāng)然知道$a的值仍然等于 而$b的值最后將是 并且此時(shí) 你還知道 Zend在盡力節(jié)省內(nèi)存 通過(guò)使$a和$b都引用相同的zval(見(jiàn)第二行代碼) 那么 當(dāng)執(zhí)行到第三行并且必須改變$b變量的值時(shí) 會(huì)發(fā)生什么情況呢? 回答是 Zend要查看refcount的值 并且確保在它的值大于 時(shí)對(duì)之進(jìn)行分離 在Zend引擎中 分離是破壞一個(gè)引用對(duì)的過(guò)程 正好與你剛才看到的過(guò)程相反
復(fù)制代碼 代碼如下: zval *get_var_and_separate(char *varname int varname_len TSRMLS_DC) { zval **varval *varcopy; if (zend_hash_find(EG(active_symbol_table) varname varname_len + (void**)varval) == FAILURE) { /* 變量根本并不存在 失敗而導(dǎo)致退出*/ return NULL; } if ((*varval) >refcount < ) { /* varname是唯一的實(shí)際引用 *不需要進(jìn)行分離 */ return *varval; } /* 否則 再?gòu)?fù)制一份zval*的值*/ MAKE_STD_ZVAL(varcopy); varcopy = *varval; /* 復(fù)制任何在zval*內(nèi)的已分配的結(jié)構(gòu)*/ zval_copy_ctor(varcopy); /*刪除舊版本的varname *這將減少該過(guò)程中varval的refcount的值 */ zend_hash_del(EG(active_symbol_table) varname varname_len + ); /*初始化新創(chuàng)建的值的引用計(jì)數(shù) 并把它依附到 * varname變量 */ varcopy >refcount = ; varcopy >is_ref = ; zend_hash_add(EG(active_symbol_table) varname varname_len + varcopy sizeof(zval*) NULL); /*返回新的zval* */ return varcopy; }
現(xiàn)在 既然引擎有一個(gè)僅為變量$b所擁有的zval*(引擎能知道這一點(diǎn)) 所以它能夠把這個(gè)值轉(zhuǎn)換成一個(gè)long型值并根據(jù)腳本的請(qǐng)求給它增加
七 寫(xiě)改變(change on write) 引用計(jì)數(shù)概念的引入還導(dǎo)致了一個(gè)新的數(shù)據(jù)操作可能性 其形式從用戶空間腳本管理器看來(lái)與"引用"有一定關(guān)系 請(qǐng)考慮下列的用戶空間代碼片斷
復(fù)制代碼 代碼如下: <?php $a = ; $b = $a; $b += ; ?>
在 上面的PHP代碼中 你能看出$a的值現(xiàn)在為 盡管它一開(kāi)始為 并且從未(直接)發(fā)生變化 之所以會(huì)發(fā)生這種情況是因?yàn)楫?dāng)引擎開(kāi)始把$b的值增加 時(shí) 它注意到$b是一個(gè)對(duì)$a的引用并且認(rèn)為"我可以改變?cè)撝刀槐胤蛛x它 因?yàn)槲蚁胧顾械囊米兞慷寄芸吹竭@一改變" 但是 引擎是如何 知道的呢?很簡(jiǎn)單 它只要查看一下zval結(jié)構(gòu)的第四個(gè)和最后一個(gè)元素(is_ref)即可 這是一個(gè)簡(jiǎn)單的開(kāi)/關(guān)位 它定義了該值是否實(shí)際上是一個(gè)用戶 空間風(fēng)格引用集的一部分 在前面的代碼片斷中 當(dāng)執(zhí)行第一行時(shí) 為$a創(chuàng)建的值得到一個(gè)refcount為 還有一個(gè)is_ref值為 因?yàn)樗鼉H為一 個(gè)變量($a)所擁有并且沒(méi)有其它變量對(duì)它產(chǎn)生寫(xiě)引用改變 在第二行 這個(gè)值的refcount元素被增加為 除了這次is_ref元素被置為 之外 (因?yàn)槟_本中包含了一個(gè)""符號(hào)以指示是完全引用) 最后 在第三行 引擎再一次取出與變量$b相關(guān)的值并且檢查是否有必要進(jìn)行分離 這一次該值沒(méi)有被分離 因?yàn)榍懊鏇](méi)有包括一個(gè)檢查 下面是get_var_and_separate()函數(shù)中與refcount檢查有關(guān)的部分代碼
復(fù)制代碼 代碼如下: if ((*varval) >is_ref || (*varval) >refcount < ) { /* varname是唯一的實(shí)際引用 * 或者它是對(duì)其它變量的一個(gè)完全引用 *任何一種方式 都沒(méi)有進(jìn)行分離 */ return *varval; }
這一次 盡管refcount為 卻沒(méi)有實(shí)現(xiàn)分離 因?yàn)檫@個(gè)值是一個(gè)完全引用 引擎能夠自由地修改它而不必關(guān)心其它變量值的變化
八 分離問(wèn)題 盡管已經(jīng)存在上面討論到的復(fù)制和引用技術(shù) 但是還存在一些不能通過(guò)is_ref和refcount操作來(lái)解決的問(wèn)題 請(qǐng)考慮下面這個(gè)PHP代碼塊
復(fù)制代碼 代碼如下: <?php $a = ; $b = $a; $c = $a; ?>
在 此 你有一個(gè)需要與三個(gè)不同的變量相關(guān)聯(lián)的值 其中 兩個(gè)變量是使用了"change on write"完全引用方式 而第三個(gè)變量處于一種可分離 的"copy on write"(寫(xiě)復(fù)制)上下文中 如果僅使用is_ref和refcount來(lái)描述這種關(guān)系 有哪些值能夠工作呢? 回答是 沒(méi)有一個(gè)能工作 在這種情況下 這個(gè)值必須被復(fù)制到兩個(gè)分離的zval*中 盡管兩者都包含完全相同的數(shù)據(jù)(見(jiàn)圖 )
圖 引用時(shí)強(qiáng)制分離
同樣 下列代碼塊將引起相同的沖突并且強(qiáng)迫該值分離出一個(gè)副本(見(jiàn)圖 )
圖 復(fù)制時(shí)強(qiáng)制分離
復(fù)制代碼 代碼如下: <?php $a = ; $b = $a; $c = $a; ?> lishixinzhi/Article/program/PHP/201311/20951
修改PHP.ini
文件
修改最大上傳值,最大POST值,最大執(zhí)行超時(shí)時(shí)間值。
如果沒(méi)有辦法更改PHP.ini,把數(shù)據(jù)結(jié)構(gòu)和數(shù)據(jù)記錄分開(kāi),數(shù)據(jù)記錄文件,手動(dòng)調(diào)整到2M
以內(nèi)
名稱欄目:php數(shù)據(jù)結(jié)構(gòu)能存多少 php的數(shù)據(jù)類(lèi)型有哪些
文章路徑:http://vcdvsql.cn/article16/dopggdg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站收錄、網(wǎng)站制作、面包屑導(dǎo)航、企業(yè)建站、品牌網(wǎng)站制作、靜態(tài)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容