php5.6與php7 不同總結(陸續補充)
php5.6的雜湊表比較噁心,php7也對雜湊表進行了改造,先介紹下php5.6的雜湊表
原來大家都清楚,我們看一下更細的一部分,如何更新插入:
static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_W(zval ***ptr, zend_uint var TSRMLS_DC) { zend_compiled_variable *cv = &CV_DEF_OF(var); if (!EG(active_symbol_table)) { Z_ADDREF(EG(uninitialized_zval)); *ptr = (zval**)EX_CV_NUM(EG(current_execute_data), EG(active_op_array)->last_var + var); **ptr = &EG(uninitialized_zval); } else if (zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) { Z_ADDREF(EG(uninitialized_zval)); zend_hash_quick_update(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, &EG(uninitialized_zval_ptr), sizeof(zval *), (void **)ptr); } return *ptr; }
注意一下
ZEND_API int _zend_hash_quick_add_or_update(HashTable *ht, const char *arKey, uint nKeyLength, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC);
zend_hash_quick_update(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, &EG(uninitialized_zval_ptr), sizeof(zval *), (void **)ptr);
首先要注意看的是&EG(uninitialized_zval_ptr)是一個**zval結構指標, 把它存進去的目的是初始化,也就是讓hash表結構指標有所指向,一個固定位置,後續會根據pDest指標進行賦值。
其次是pDest是二級指標,為什麼會是二級指標,因為c語言函式傳遞都是值傳遞,要改變指標值只能將指標地址傳入。
但是雖然是二級指標,事實呼叫的卻是用的三級真值***ptr,那是因為符號表變數存的永遠是**zval結構,加上ptr變數地址,所以三級就是這樣來的。
#define UPDATE_DATA(ht, p, pData, nDataSize) \ if (nDataSize == sizeof(void*)) { \ if ((p)->pData != &(p)->pDataPtr) { \ pefree_rel((p)->pData, (ht)->persistent); \ } \ memcpy(&(p)->pDataPtr, pData, sizeof(void *)); \ (p)->pData = &(p)->pDataPtr; \ } else { \ if ((p)->pData == &(p)->pDataPtr) { \ (p)->pData = (void *) pemalloc_rel(nDataSize, (ht)->persistent); \ (p)->pDataPtr=NULL; \ } else { \ (p)->pData = (void *) perealloc_rel((p)->pData, nDataSize, (ht)->persistent); \ /* (p)->pDataPtr is already NULL so no need to initialize it */ \ } \ memcpy((p)->pData, pData, nDataSize); \ }
開始把memcpy函式搞錯了,是指標指向的內容進行拷貝,所以p->pDataPtr存放的是一級指標*zval
具體看下面畫的很難看的圖
接下來是php7的資料結構:
struct _zend_string {
zend_refcounted_h gc;
zend_ulong h; /* hash value */
size_t len;
char val[1];
};
typedef struct _Bucket {
zval val;
zend_ulong h; /* hash value (or numeric index) */
zend_string *key; /* string key or NULL for numerics */
} Bucket;
typedef struct _zend_array HashTable;
struct _zend_array {
zend_refcounted_h gc;
union {
struct {
ZEND_ENDIAN_LOHI_4(
zend_uchar flags,
zend_uchar nApplyCount,
zend_uchar nIteratorsCount,
zend_uchar reserve)
} v;
uint32_t flags;
} u;
uint32_t nTableMask;
Bucket *arData;
uint32_t nNumUsed;
uint32_t nNumOfElements;
uint32_t nTableSize;
uint32_t nInternalPointer;
zend_long nNextFreeElement;
dtor_func_t pDestructor;
};
/*
* HashTable Data Layout
* =====================
*
* +=============================+
* | HT_HASH(ht, ht->nTableMask) |
* | ... |
* | HT_HASH(ht, -1) |
* +-----------------------------+
* ht->arData ---> | Bucket[0] |
* | ... |
* | Bucket[ht->nTableSize-1] |
* +=============================+
*/
ht->arData僅是一級指標,分為上下兩部分,上部分是索引根據hash值偏移獲取下半部分的index,從而拿到內容
<pre style="font-family: NSimSun; font-size: 16px; background: white;"><span style="color:blue;">#define</span> HT_HASH_EX(data, idx) \
((uint32_t*)(data))[(int32_t)(idx)]
根據hash值獲取int型別的偏移量,通常idx為負數見初始化:
static void zend_always_inline zend_hash_real_init_ex(HashTable *ht, int packed)
{
HT_ASSERT(GC_REFCOUNT(ht) == 1);
ZEND_ASSERT(!((ht)->u.flags & HASH_FLAG_INITIALIZED));
if (packed) {
HT_SET_DATA_ADDR(ht, pemalloc(HT_SIZE(ht), (ht)->u.flags & HASH_FLAG_PERSISTENT));
(ht)->u.flags |= HASH_FLAG_INITIALIZED | HASH_FLAG_PACKED;
HT_HASH_RESET_PACKED(ht);
} else {
(ht)->nTableMask = -(ht)->nTableSize;
HT_SET_DATA_ADDR(ht, pemalloc(HT_SIZE(ht), (ht)->u.flags & HASH_FLAG_PERSISTENT));
(ht)->u.flags |= HASH_FLAG_INITIALIZED;
if (EXPECTED(ht->nTableMask == -8)) {
Bucket *arData = ht->arData;
HT_HASH_EX(arData, -8) = -1;
HT_HASH_EX(arData, -7) = -1;
HT_HASH_EX(arData, -6) = -1;
HT_HASH_EX(arData, -5) = -1;
HT_HASH_EX(arData, -4) = -1;
HT_HASH_EX(arData, -3) = -1;
HT_HASH_EX(arData, -2) = -1;
HT_HASH_EX(arData, -1) = -1;
} else {
HT_HASH_RESET(ht);
}
}
}
# define HT_HASH_TO_BUCKET_EX(data, idx) \ ((Bucket*)((char*)(data) + (idx)))根據上面獲取的偏移量獲取bucket指標
可見增加元素的方法
add_to_hash:
HANDLE_BLOCK_INTERRUPTIONS();
idx = ht->nNumUsed++;
ht->nNumOfElements++;
if (ht->nInternalPointer == HT_INVALID_IDX) {
ht->nInternalPointer = idx;
}
zend_hash_iterators_update(ht, HT_INVALID_IDX, idx);
p = ht->arData + idx;
p->key = key;
if (!ZSTR_IS_INTERNED(key)) {
zend_string_addref(key);
ht->u.flags &= ~HASH_FLAG_STATIC_KEYS;
zend_string_hash_val(key);
}
p->h = h = ZSTR_H(key);
ZVAL_COPY_VALUE(&p->val, pData);
nIndex = h | ht->nTableMask;
Z_NEXT(p->val) = HT_HASH(ht, nIndex);
HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
HANDLE_UNBLOCK_INTERRUPTIONS();
首先zval元素的位置是順序儲存的,就是ht->arData的下半部分,然後通過hash算出nIndex位移即上部分,首先將上部分的初始位置(-1)賦值給下半部分zval的next屬性,然後賦值為下部分的位置(1),如此迴圈,當加入一個新的hash相同的資料時,此時將1賦值給新的zval的next,上部分的值為2。
2 $var = 1
php7解析過程 :
compile_file -> zendparse(yyparse) -> zend_compile_top_stmt -> zend_compile_stmt-> zend_compile_assign -> zend_compile_simple_var -> zend_try_compile_cv -> zend_compile_simple_var_no_cv
獲取opcode
相關推薦
php5.6與php7 不同總結(陸續補充)
php5.6的雜湊表比較噁心,php7也對雜湊表進行了改造,先介紹下php5.6的雜湊表 原來大家都清楚,我們看一下更細的一部分,如何更新插入: static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_W(zv
自我記錄:C語言編寫程式碼可能發生的問題與注意事項【陸續補充】
前言:該文章原創,不僅針對新手還是老手,均有一定幫助。若有錯誤地方,請不惜賜教。主要結合《C與指標》這本書,後續看過《C專家程式設計》、《C語言的XXX個問題》等書後會繼續補充。【非計算機類學生,目前更新進度緩慢】 編寫程式碼前的注意: ①、程式設計風格影響程式碼的可讀性,這像是一個人的臉,
isset在php5.6-和php7.0+的一些差異
今天在公司實現一個模組功能時寫了如下程式碼: class ProductCategory { const TYPES = [ 1 => 'type1', 2 => 'type2', ]; public func
PHP5.6 和PHP7.0區別 PHP5.6 和PHP7.0區別
PHP5.6 和PHP7.0區別 1. PHP7.0 比PHP5.6效能提升了兩倍。 2.PHP7.0全面一致支援64位。 3.PHP7.0之前出現的致命錯誤,都改成了丟擲異常。 4.增加了空結合操作符(??)。效果相當於三元運算子。 5.PHP7
PHP多版本共存:php5.6與php5.5共存
續: php多版本共存,需要使用php-fpm來執行php方便,這樣更方便配置和管理 準備工作: 建立PHP5.6的相關目錄,不要與已安裝的php5.5的目錄相同 mkdir /usr/local/php56 安裝目錄 mkdir /etc/ph
基於MAC的 LNMP環境搭建, PHP5.6,PHP7.2.3 雜記
sudo ./configure --prefix=/Users/heweijun/www/server/php --with-config-file-path=/Users/heweijun/www/server/php/etc --enable-fpm --with-fpm-user=www --wit
PHP5.6 和PHP7.0區別
1. PHP7.0 比PHP5.6效能提升了兩倍。2.PHP7.0全面一致支援64位。3.PHP7.0之前出現的致命錯誤,都改成了丟擲異常。4.增加了空結合操作符(??)。效果相當於三元運算子。5.PHP7.0新增了函式的返回型別宣告。6.PHP7.0新增了標量型別宣告。 PHP 7 中的函式的形參型別宣告
Ubuntu 16.04 PHP5.6和PHP7.2共存 LNMP
因為公司專案跑PHP5.6,而自己學習需要PHP7.2,所以需要這兩個版本共存.LNMP的搭建 首先搭建的是5.6的版本 不影響 在此基礎上再安裝一個PHP7.2ppa 方式安裝 php7.2 :sudo apt-get install software-properties
Apache2.4 與 php7.1.6的鏈接
pin php png 4.2 啟動 .cn ica 1-1 image 首先Apache已經安裝成功,在瀏覽器中能夠打開再下載php 我的Apache安裝版本為Apache2.4.26 x64 vc14 所以我php也應該是vc14編譯的 php下載地址為 http://
PHP7有沒有你們說的那麽牛逼(php7.1 和 php5.6 橫向對比) 轉載
ber bug maria 現在 bin grep creat -h incr 轉自 https://www.jianshu.com/p/5baa78646a79 PHP7來一發 PHP7正式發布到現在已經一年半了,剛出道就號稱比舊版本快了幾倍,各種開源框架或系統運行
ccentos 7下安裝php5.6並使用nginx + php-fpm部署多個不同端口網站
png .net 又一 介紹 htm sea tip 編輯 端口 作為一個的勤雜工,近期因公司內部信息化的需求,給新進員工提供基礎的知識培訓和介紹,也為了給公司內部建立一個溝通交流的平臺,百度找了開源的百科系統HDwiki和開源的問答系統Tipask問答系統,蛋痛的這兩套系
php5.5和php7.2 方括號賦值的不同區別結果 (織夢升級到php7除錯後臺無法刪除欄目的問題)
php5.5和php7.2 方括號賦值的不同區別結果 織夢升級到php7除錯後臺無法刪除欄目的問題程式碼簡化例子如下: <?php /** * */ class TestName { var $string; var $arr; function __con
CentOS6.8中原php5.6升級成php7.2方法
因為laravel框架的基本要求,必須將原伺服器上的php5.6升級成php7.2才可以。以下是自己的操作步驟。 yum remove php* 參照右邊連結: intall-php7-in-centos6 操作 因為上文中沒有安裝php-fpm所以還要執行yum
linux下編譯安裝php7(相容現有的php5.6版本)
1.首先去php官網下載一個php7版本原始碼包 http://php.net/downloads.php,我這下載的是php7.2.13版本. 2.使用ftp或者linux的rz命令將包上傳到linux下,開始進行編譯安裝. 3.解壓安裝包 # tar -zxvf
PHP5.6將退出版本之爭,PHP7的時代將全面來臨(PHP7.3)
PHP背景: PHP5.6作為PHP5的最後一個版本,也是目前國內使用最廣泛的PHP版本,PHP 5.6始於2014年。其第一個測試版PHP 5.6 alpha 1版於2014年1月釋出。隨機產生了第一個由國人(鳥哥,惠新宸
Ubuntu16.04 PHP7 TO PHP5.6
PHP7 TO PHP5.6 remove PHP installed List the installed php pkg root@VM-13-184-ubuntu:~# dpkg -l | grep php7 ii libapache2-mo
ubuntu 16 php7 降級 php5.6
sudo dpkg -l | grep php| awk '{print $2}' |tr "\n" " " sudo apt-get install aptitude sudo aptitude purge `dpkg -l | grep php| awk '{print
ubuntu 使用apt-get install 安裝php5.6--php7
使用ppa增加源: $ sudo apt-get install python-software-properties $ sudo add-apt-repository ppa:ondrej/php $ sudo apt-get update $ sud
Centos 7 搭建LAMP(apache2.4+php5.6/php7+mysql)
1、下載apache 服務 yum -y install httpd 開啟apache systemctl start httpd 設定開啟自啟動 systemctl enbale httpd2、安裝mysql yum install mariadb mariadb-se
ubuntu解除安裝php7並安裝php5.6記錄
ubuntu16.04版本從預設源安裝的php版本為7.x版本,我們都知道php7.0已經捨棄了很多舊版本的函式等內容,這對舊系統來說是致命的,那麼,我們就有了安裝舊版php的需求,而同一主機安裝兩個版本的php,如果不做配置會報錯。那麼,我們就需要:一、解除安裝ph