成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

【PHP7源碼分析】如何理解PHP虛擬機(jī)(一)

tunny / 2455人閱讀

摘要:操作數(shù)本身并無(wú)數(shù)據(jù)類(lèi)型,它的數(shù)據(jù)類(lèi)型由操作碼確定任何架構(gòu)的計(jì)算機(jī)都會(huì)對(duì)外提供指令集合運(yùn)算器通過(guò)執(zhí)行指令直接發(fā)出控制信號(hào)控制計(jì)算機(jī)各項(xiàng)操作。

順風(fēng)車(chē)運(yùn)營(yíng)研發(fā)團(tuán)隊(duì) 李樂(lè)

1.從物理機(jī)說(shuō)起

虛擬機(jī)也是計(jì)算機(jī),設(shè)計(jì)思想和物理機(jī)有很多相似之處;

1.1馮諾依曼體系結(jié)構(gòu)

馮·諾依曼是當(dāng)之無(wú)愧的數(shù)字計(jì)算機(jī)之父,當(dāng)前計(jì)算機(jī)都采用的是馮諾依曼體系結(jié)構(gòu);設(shè)計(jì)思想主要包含以下幾個(gè)方面:

指令和數(shù)據(jù)不加區(qū)別混合存儲(chǔ)在同一個(gè)存儲(chǔ)器中,它們都是內(nèi)存中的數(shù)據(jù)。現(xiàn)代CPU的保護(hù)模式,每個(gè)內(nèi)存段都有段描述符,這個(gè)描述符記錄著這個(gè)內(nèi)存段的訪問(wèn)權(quán)限(可讀,可寫(xiě),可執(zhí)行)。這就變相的指定了哪些內(nèi)存中存儲(chǔ)的是指令哪些是數(shù)據(jù));

存儲(chǔ)器是按地址訪問(wèn)的線性編址的一維結(jié)構(gòu),每個(gè)單元的位數(shù)是固定的;

數(shù)據(jù)以二進(jìn)制表示;

指令由操作碼和操作數(shù)組成。操作碼指明本指令的操作類(lèi)型,操作數(shù)指明操作數(shù)本身或者操作數(shù)的地址。操作數(shù)本身并無(wú)數(shù)據(jù)類(lèi)型,它的數(shù)據(jù)類(lèi)型由操作碼確定;任何架構(gòu)的計(jì)算機(jī)都會(huì)對(duì)外提供指令集合;

運(yùn)算器通過(guò)執(zhí)行指令直接發(fā)出控制信號(hào)控制計(jì)算機(jī)各項(xiàng)操作。由指令計(jì)數(shù)器指明待執(zhí)行指令所在的內(nèi)存地址。指令計(jì)數(shù)器只有一個(gè),一般按順序遞增,但執(zhí)行順序可能因?yàn)檫\(yùn)算結(jié)果或當(dāng)時(shí)的外界條件而改變;

1.2匯編語(yǔ)言簡(jiǎn)介

任何架構(gòu)的計(jì)算機(jī)都會(huì)提供一組指令集合;

指令由操作碼和操作數(shù)組成;操作碼即操作類(lèi)型,操作數(shù)可以是一個(gè)立即數(shù)或者一個(gè)存儲(chǔ)地址;每條指令可以有0、1或2個(gè)操作數(shù);

指令就是一串二進(jìn)制;匯編語(yǔ)言是二進(jìn)制指令的文本形式;

push   %ebx
mov    %eax, [%esp+8]
mov    %ebx, [%esp+12]
add    %eax, %ebx
pop    %ebx

push、mov、add、pop等就是操作碼;
%ebx寄存器;[%esp+12]內(nèi)存地址;
操作數(shù)只是一塊可存取數(shù)據(jù)的存儲(chǔ)區(qū);操作數(shù)本身并無(wú)數(shù)據(jù)類(lèi)型,它的數(shù)據(jù)類(lèi)型由操作碼確定;
如movb傳送字節(jié),movw傳送字,movl傳送雙字等

1.3 函數(shù)調(diào)用棧

過(guò)程(函數(shù))是對(duì)代碼的封裝,對(duì)外暴露的只是一組指定的參數(shù)和一個(gè)可選的返回值;可以在程序中不同的地方調(diào)用這個(gè)函數(shù);假設(shè)過(guò)程P調(diào)用過(guò)程Q,Q執(zhí)行后返回過(guò)程P;為了實(shí)現(xiàn)這一功能,需要考慮三點(diǎn):

指令跳轉(zhuǎn):進(jìn)入過(guò)程Q的時(shí)候,程序計(jì)數(shù)器必須被設(shè)置為Q的代碼的起始地址;在返回時(shí),程序計(jì)數(shù)器需要設(shè)置為P中調(diào)用Q后面那條指令的地址;

數(shù)據(jù)傳遞:P能夠向Q提供一個(gè)或多個(gè)參數(shù),Q能夠向P返回一個(gè)值;

內(nèi)存分配與釋放:Q開(kāi)始執(zhí)行時(shí),可能需要為局部變量分配內(nèi)存空間,而在返回前,又需要釋放這些內(nèi)存空間;

大多數(shù)的語(yǔ)言過(guò)程調(diào)用都采用了棧數(shù)據(jù)結(jié)構(gòu)提供的內(nèi)存管理機(jī)制;如下圖所示:

函數(shù)的調(diào)用與返回即對(duì)應(yīng)的是一系列的入棧與出棧操作;
函數(shù)在執(zhí)行時(shí),會(huì)有自己私有的棧幀,局部變量就是分配在函數(shù)私有棧幀上的;
平時(shí)遇到的棧溢出就是因?yàn)檎{(diào)用函數(shù)層級(jí)過(guò)深,不斷入棧導(dǎo)致的;

2.PHP虛擬機(jī)

虛擬機(jī)也是計(jì)算機(jī),參考物理機(jī)的設(shè)計(jì),設(shè)計(jì)虛擬機(jī)時(shí),首先應(yīng)該考慮三個(gè)要素:指令,數(shù)據(jù)存儲(chǔ),函數(shù)棧幀;

下面從這三點(diǎn)詳細(xì)分析PHP虛擬機(jī)的設(shè)計(jì)思路;

2.1指令 2.1.1 指令類(lèi)型

任何架構(gòu)的計(jì)算機(jī)都需要對(duì)外提供一組指令集,其代表計(jì)算機(jī)支持的一組操作類(lèi)型;

PHP虛擬機(jī)對(duì)外提供186種指令,定義在zend_vm_opcodes.h文件中;

//加、減、乘、除等
#define ZEND_ADD                               1
#define ZEND_SUB                               2
#define ZEND_MUL                               3
#define ZEND_DIV                               4
#define ZEND_MOD                               5
#define ZEND_SL                                6
#define ZEND_SR                                7
#define ZEND_CONCAT                            8
#define ZEND_BW_OR                             9
#define ZEND_BW_AND                           10
……………………
2.1.2 指令 2.1.2.1指令的表示

指令由操作碼和操作數(shù)組成;操作碼指明本指令的操作類(lèi)型,操作數(shù)指明操作數(shù)本身或者操作數(shù)的地址;

PHP虛擬機(jī)定義指令格式為:操作碼 操作數(shù)1 操作數(shù)2 返回值;其使用結(jié)構(gòu)體_zend_op表示一條指令:

struct _zend_op {
    const void *handler;    //指針,指向當(dāng)前指令的執(zhí)行函數(shù)
    znode_op op1;           //操作數(shù)1         
    znode_op op2;           //操作數(shù)2
    znode_op result;        //返回值
    uint32_t extended_value;//擴(kuò)展
    uint32_t lineno;        //行號(hào)
    zend_uchar opcode;      //指令類(lèi)型
    zend_uchar op1_type;    //操作數(shù)1的類(lèi)型(此類(lèi)型并不代表字符串、數(shù)組等數(shù)據(jù)類(lèi)型;其表示此操作數(shù)是常量,臨時(shí)變量,編譯變量等)
    zend_uchar op2_type;    //操作數(shù)2的類(lèi)型
    zend_uchar result_type; //返回值的類(lèi)型
};
2.1.2.2 操作數(shù)的表示

從上面可以看到,操作數(shù)使用結(jié)構(gòu)體znode_op表示,定義如下:

constant、var、num等都是uint32_t類(lèi)型的,這怎么表示一個(gè)操作數(shù)呢?(既不是指針不能代表地址,也無(wú)法表示所有數(shù)據(jù)類(lèi)型);
其實(shí),操作數(shù)大多情況采用的相對(duì)地址表示方式,constant等表示的是相對(duì)于執(zhí)行棧幀首地址的偏移量;
另外,_znode_op結(jié)構(gòu)體中有個(gè)zval *zv字段,其也可以表示一個(gè)操作數(shù),這個(gè)字段是一個(gè)指針,指向的是zval結(jié)構(gòu)體,PHP虛擬機(jī)支持的所有數(shù)據(jù)類(lèi)型都使用zval結(jié)構(gòu)體表示;

typedef union _znode_op {
        uint32_t      constant;
        uint32_t      var;
        uint32_t      num;
        uint32_t      opline_num;
    #if ZEND_USE_ABS_JMP_ADDR
        zend_op       *jmp_addr;
    #else
        uint32_t      jmp_offset;
    #endif
    #if ZEND_USE_ABS_CONST_ADDR
        zval          *zv;
    #endif
} znode_op;
2.2 數(shù)據(jù)存儲(chǔ)

PHP虛擬機(jī)支持多種數(shù)據(jù)類(lèi)型:整型、浮點(diǎn)型、字符串、數(shù)組,對(duì)象等;PHP虛擬機(jī)如何存儲(chǔ)和表示多種數(shù)據(jù)類(lèi)型?

2.1.2.2節(jié)指出結(jié)構(gòu)體_znode_op代表一個(gè)操作數(shù);操作數(shù)可以是一個(gè)偏移量(計(jì)算得到一個(gè)地址,即zval結(jié)構(gòu)體的首地址),或者一個(gè)zval指針;PHP虛擬機(jī)使用zval結(jié)構(gòu)體表示和存儲(chǔ)多種數(shù)據(jù);

struct _zval_struct {
    zend_value        value;            //存儲(chǔ)實(shí)際的value值
    union {
        struct {                        //一些標(biāo)志位
            ZEND_ENDIAN_LOHI_4(
                zend_uchar    type,         //重要;表示變量類(lèi)型
                zend_uchar    type_flags,
                zend_uchar    const_flags,
                zend_uchar    reserved)     /* call info for EX(This) */
        } v;
        uint32_t type_info;
    } u1;
    union {                                 //其他有用信息
        uint32_t     next;                 /* hash collision chain */
        uint32_t     cache_slot;           /* literal cache slot */
        uint32_t     lineno;               /* line number (for ast nodes) */
        uint32_t     num_args;             /* arguments number for EX(This) */
        uint32_t     fe_pos;               /* foreach position */
        uint32_t     fe_iter_idx;          /* foreach iterator index */
        uint32_t     access_flags;         /* class constant access flags */
        uint32_t     property_guard;       /* single property guard */
    } u2;
};

zval.u1.type表示數(shù)據(jù)類(lèi)型, zend_types.h文件定義了以下類(lèi)型:

#define IS_UNDEF                    0
#define IS_NULL                     1
#define IS_FALSE                    2
#define IS_TRUE                     3
#define IS_LONG                     4
#define IS_DOUBLE                   5
#define IS_STRING                   6
#define IS_ARRAY                    7
#define IS_OBJECT                   8
#define IS_RESOURCE                 9
#define IS_REFERENCE                10
…………

zend_value存儲(chǔ)具體的數(shù)據(jù)內(nèi)容,結(jié)構(gòu)體定義如下:

_zend_value占16字節(jié)內(nèi)存;long、double類(lèi)型會(huì)直接存儲(chǔ)在結(jié)構(gòu)體;引用、字符串、數(shù)組等類(lèi)型使用指針存儲(chǔ);

代碼中根據(jù)zval.u1.type字段,判斷數(shù)據(jù)類(lèi)型,以此決定操作_zend_value結(jié)構(gòu)體哪個(gè)字段;

可以看出,字符串使用zend_string表示,數(shù)組使用zend_array表示…

typedef union _zend_value {
    zend_long         lval;            
    double            dval;            
    zend_refcounted  *counted;
    zend_string      *str;
    zend_array       *arr;
    zend_object      *obj;
    zend_resource    *res;
    zend_reference   *ref;
    zend_ast_ref     *ast;
    zval             *zv;
    void             *ptr;
    zend_class_entry *ce;
    zend_function    *func;
    struct {
        uint32_t w1;
        uint32_t w2;
    } ww;
} zend_value;

如下圖為PHP7中字符串結(jié)構(gòu)圖:

2.3 再談指令

2.1.2.1指出,指令使用結(jié)構(gòu)體_zend_op表示;其中最主要2個(gè)屬性:操作函數(shù),操作數(shù)(兩個(gè)操作數(shù)和一個(gè)返回值);

操作數(shù)的類(lèi)型(常量、臨時(shí)變量等)不同,同一個(gè)指令對(duì)應(yīng)的handler函數(shù)也會(huì)不同;操作數(shù)類(lèi)型定義在 Zend/zend_compile.h文件:

//常量
#define IS_CONST    (1<<0)
 
//臨時(shí)變量,用于操作的中間結(jié)果;不能被其他指令對(duì)應(yīng)的handler重復(fù)使用
#define IS_TMP_VAR  (1<<1)
 
//這個(gè)變量并不是PHP代碼中聲明的變量,常見(jiàn)的是返回的臨時(shí)變量,比如$a=time(), 函數(shù)time返回值的類(lèi)型就是IS_VAR,這種類(lèi)型的變量是可以被其他指令對(duì)應(yīng)的handler重復(fù)使用的
#define IS_VAR      (1<<2)
#define IS_UNUSED   (1<<3)  /* Unused variable */
 
//編譯變量;即PHP中聲明的變量;
#define IS_CV       (1<<4)  /* Compiled variable */

操作函數(shù)命名規(guī)則為:ZEND_[opcode]_SPEC_(操作數(shù)1類(lèi)型)_(操作數(shù)2類(lèi)型)_(返回值類(lèi)型)_HANDLER

比如賦值語(yǔ)句就有以下多種操作函數(shù):

ZEND_ASSIGN_SPEC_VAR_CONST_RETVAL_UNUSED_HANDLER,
ZEND_ASSIGN_SPEC_VAR_TMP_RETVAL_UNUSED_HANDLER,
ZEND_ASSIGN_SPEC_VAR_VAR_RETVAL_UNUSED_HANDLER,
ZEND_ASSIGN_SPEC_VAR_CV_RETVAL_UNUSED_HANDLER,
…

對(duì)于$a=1,其操作函數(shù)為: ZEND_ASSIGN_SPEC_CV_CONST_RETVAL_UNUSED_HANDLER;函數(shù)實(shí)現(xiàn)為:

static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_CONST_RETVAL_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
    USE_OPLINE
 
    zval *value;
    zval *variable_ptr;
 
    SAVE_OPLINE();
    //獲取op2對(duì)應(yīng)的值,也就是1
    value = EX_CONSTANT(opline->op2);
    //在execute_data中獲取op1的位置,也就是$a(execute_data類(lèi)似函數(shù)棧幀,后面詳細(xì)分析)
    variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var);
     
    //賦值
    value = zend_assign_to_variable(variable_ptr, value, IS_CONST);
    if (UNEXPECTED(0)) {
        ZVAL_COPY(EX_VAR(opline->result.var), value);
    }
 
    ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
2.4 函數(shù)棧幀 2.4.1指令集

上面分析了指令的結(jié)構(gòu)與表示,PHP虛擬機(jī)使用_zend_op_array表示指令的集合:

struct _zend_op_array {
    …………
    //last表示指令總數(shù);opcodes為存儲(chǔ)指令的數(shù)組;
    uint32_t last;
    zend_op *opcodes;
    //變量類(lèi)型為IS_CV的個(gè)數(shù)
    int last_var;
    //變量類(lèi)型為IS_VAR和IS_TEMP_VAR的個(gè)數(shù)
    uint32_t T;
    //存放IS_CV類(lèi)型變量的數(shù)組
    zend_string **vars;
 
    …………
     
    //靜態(tài)變量
    HashTable *static_variables;
 
    //常量個(gè)數(shù);常量數(shù)組
    int last_literal;
    zval *literals;
 
    …
};

注意: last_var代表IS_CV類(lèi)型變量的個(gè)數(shù),這種類(lèi)型變量存放在vars數(shù)組中;在整個(gè)編譯過(guò)程中,每次遇到一個(gè)IS_CV類(lèi)型的變量(類(lèi)似于$something),就會(huì)去遍歷vars數(shù)組,檢查是否已經(jīng)存在,如果不存在,則插入到vars中,并將last_var的值設(shè)置為該變量的操作數(shù);如果存在,則使用之前分配的操作數(shù)

2.4.2 函數(shù)棧幀

PHP虛擬機(jī)實(shí)現(xiàn)了與1.3節(jié)物理機(jī)類(lèi)似的函數(shù)棧幀結(jié)構(gòu);

使用 _zend_vm_stack表示棧結(jié)構(gòu);多個(gè)棧之間使用prev字段形成單向鏈表;top和end指向棧低和棧頂,分別為zval類(lèi)型的指針;

struct _zend_vm_stack {
    zval *top;
    zval *end;
    zend_vm_stack prev;
};

考慮如何設(shè)計(jì)函數(shù)執(zhí)行時(shí)候的幀結(jié)構(gòu):當(dāng)前函數(shù)執(zhí)行時(shí),需要存儲(chǔ)函數(shù)編譯后的指令,需要存儲(chǔ)函數(shù)內(nèi)部的局部變量等(2.1.2.2節(jié)指出,操作數(shù)使用結(jié)構(gòu)體znode_op表示,其內(nèi)部使用uint32_t表示操作數(shù),此時(shí)表示的就是當(dāng)前zval變量相對(duì)于當(dāng)前函數(shù)棧幀首地址的偏移量);

PHP虛擬機(jī)使用結(jié)構(gòu)體_zend_execute_data存儲(chǔ)當(dāng)前函數(shù)執(zhí)行所需數(shù)據(jù);

struct _zend_execute_data {
    //當(dāng)前指令指令
    const zend_op       *opline; 
    //當(dāng)前函數(shù)執(zhí)行棧幀
    zend_execute_data   *call; 
    //函數(shù)返回?cái)?shù)據(jù)          
    zval                *return_value;
    zend_function       *func;            
    zval                 This;      /* this + call_info + num_args */
    //調(diào)用當(dāng)前函數(shù)的棧幀       
    zend_execute_data   *prev_execute_data;
    //符號(hào)表
    zend_array          *symbol_table;
#if ZEND_EX_USE_RUN_TIME_CACHE
    void               **run_time_cache;  
#endif
#if ZEND_EX_USE_LITERALS
    //常量數(shù)組
    zval                *literals;        
#endif
};

函數(shù)開(kāi)始執(zhí)行時(shí),需要為函數(shù)分配相應(yīng)的函數(shù)棧幀并入棧,代碼如下:

static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(uint32_t call_info, zend_function *func, uint32_t num_args, zend_class_entry *called_scope, zend_object *object)
{
    //計(jì)算當(dāng)前函數(shù)棧幀需要內(nèi)存空間大小
    uint32_t used_stack = zend_vm_calc_used_stack(num_args, func);
 
    //根據(jù)棧幀大小分配空間,入棧
    return zend_vm_stack_push_call_frame_ex(used_stack, call_info,
        func, num_args, called_scope, object);
}
 
//計(jì)算函數(shù)棧幀大小
static zend_always_inline uint32_t zend_vm_calc_used_stack(uint32_t num_args, zend_function *func)
{
    //_zend_execute_data大?。?0字節(jié)/16字節(jié)=5)+參數(shù)數(shù)目
    uint32_t used_stack = ZEND_CALL_FRAME_SLOT + num_args;
 
    if (EXPECTED(ZEND_USER_CODE(func->type))) {
        //當(dāng)前函數(shù)臨時(shí)變量等數(shù)目
        used_stack += func->op_array.last_var + func->op_array.T - MIN(func->op_array.num_args, num_args);
    }
 
    //乘以16字節(jié)
    return used_stack * sizeof(zval);
}
 
//入棧
static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame_ex(uint32_t used_stack, uint32_t call_info, zend_function *func, uint32_t num_args, zend_class_entry *called_scope, zend_object *object)
{
    //上一個(gè)函數(shù)棧幀地址
    zend_execute_data *call = (zend_execute_data*)EG(vm_stack_top);
 
    //移動(dòng)函數(shù)調(diào)用棧top指針
    EG(vm_stack_top) = (zval*)((char*)call + used_stack);
    //初始化當(dāng)前函數(shù)棧幀
    zend_vm_init_call_frame(call, call_info, func, num_args, called_scope, object);
    //返回當(dāng)前函數(shù)棧幀首地址
    return call;
}

從上面分析可以得到函數(shù)棧幀結(jié)構(gòu)圖如下所示:

總結(jié)

PHP虛擬機(jī)也是計(jì)算機(jī),有三點(diǎn)是我們需要重點(diǎn)關(guān)注的:指令集(包含指令處理函數(shù))、數(shù)據(jù)存儲(chǔ)(zval)、函數(shù)棧幀;

此時(shí)虛擬機(jī)已可以接受指令并執(zhí)行指令代碼;

但是,PHP虛擬機(jī)是專(zhuān)用執(zhí)行PHP代碼的,PHP代碼如何能轉(zhuǎn)換為PHP虛擬機(jī)可以識(shí)別的指令呢——編譯;

PHP虛擬機(jī)同時(shí)提供了編譯器,可以將PHP代碼轉(zhuǎn)換為其可以識(shí)別的指令集合;

理論上你可以自定義任何語(yǔ)言,只要實(shí)現(xiàn)編譯器,能夠?qū)⒛阕约旱恼Z(yǔ)言轉(zhuǎn)換為PHP可以識(shí)別的指令代碼,就能被PHP虛擬機(jī)執(zhí)行;

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/29184.html

相關(guān)文章

  • PHP7源碼分析PHP7語(yǔ)言的執(zhí)行原理

    摘要:在中,源代碼首先將進(jìn)行詞法分析,將源代碼切割為多個(gè)字符串單元,分割后的字符串稱(chēng)之為。圖以為例解釋型語(yǔ)言的執(zhí)行示意圖第步源碼通過(guò)詞法分析得到第步基于語(yǔ)法分析器生成抽象語(yǔ)法樹(shù)第步抽象語(yǔ)法樹(shù)轉(zhuǎn)換為指令集合,解釋執(zhí)行。 順風(fēng)車(chē)運(yùn)營(yíng)研發(fā)團(tuán)隊(duì) 李志 發(fā)表在程序人生 公眾號(hào)我們常用的高級(jí)語(yǔ)言有很多種,比較出名的有CC++、Python、 PHP、Go、Pascal等。而這些語(yǔ)言根據(jù)運(yùn)行的方式不同,...

    VEIGHTZ 評(píng)論0 收藏0
  • PHP7源碼分析PHP7源碼研究之淺談Zend虛擬機(jī)

    摘要:中詞法語(yǔ)法分析,生成抽象語(yǔ)法樹(shù),然后編譯成及被執(zhí)行均由虛擬機(jī)完成。通常情況下這部分是可選部分,主要為便于程序的讀寫(xiě)方便而使用。指令虛擬機(jī)的指令稱(chēng)為,每條指令對(duì)應(yīng)一個(gè)。 作者 陳雷編程語(yǔ)言的虛擬機(jī)是一種可以運(yùn)行中間語(yǔ)言的程序。中間語(yǔ)言是抽象出的指令集,由原生語(yǔ)言編譯而成,作為虛擬機(jī)執(zhí)行階段的輸入。很多語(yǔ)言都實(shí)現(xiàn)了自己的虛擬機(jī),比如Java、C#和Lua。PHP語(yǔ)言也有自己的虛擬機(jī),稱(chēng)為Z...

    馬龍駒 評(píng)論0 收藏0
  • PHP小知識(shí)點(diǎn)

    摘要:那些瑣碎的知識(shí)點(diǎn)作者記錄的的很奇特很難記的知識(shí)點(diǎn)。易錯(cuò)知識(shí)點(diǎn)整理注意和的區(qū)別中和都是輸出的作用,但是兩者之間還是有細(xì)微的差別。今天手頭不忙,總結(jié)一下,分享過(guò)程中掌握的知識(shí)點(diǎn)。 深入理解 PHP 之:Nginx 與 FPM 的工作機(jī)制 這篇文章從 Nginx 與 FPM 的工作機(jī)制出發(fā),探討配置背后的原理,讓我們真正理解 Nginx 與 PHP 是如何協(xié)同工作的。 PHP 那些瑣碎的知識(shí)...

    hover_lew 評(píng)論0 收藏0
  • PHP7源碼分析PHP7到底有多快,基準(zhǔn)測(cè)試與特性分析告訴你

    摘要:我們修改上面代碼,再來(lái)看下返回值類(lèi)型限制的情況運(yùn)行結(jié)果這段代碼我們額外聲明了返回值的類(lèi)型為型。對(duì)函數(shù)返回值的聲明做了擴(kuò)充,可以定義其返回值為,無(wú)論是否開(kāi)啟嚴(yán)格模式,只要函數(shù)中有以外的其他語(yǔ)句都會(huì)報(bào)錯(cuò)。 順風(fēng)車(chē)運(yùn)營(yíng)研發(fā)團(tuán)隊(duì) 王坤 發(fā)表至21CTO公眾號(hào)(https://mp.weixin.qq.com/s/ph...) showImg(https://segmentfault.c...

    Towers 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<